diff --git a/compiler/tests/org/jetbrains/kotlin/serialization/js/KotlinJavascriptSerializerTest.kt b/compiler/tests/org/jetbrains/kotlin/serialization/js/KotlinJavascriptSerializerTest.kt index 3e44663a521..fce2c0879a7 100644 --- a/compiler/tests/org/jetbrains/kotlin/serialization/js/KotlinJavascriptSerializerTest.kt +++ b/compiler/tests/org/jetbrains/kotlin/serialization/js/KotlinJavascriptSerializerTest.kt @@ -79,9 +79,10 @@ class KotlinJavascriptSerializerTest : TestCaseWithTmpdir() { imported = listOf(), data = analysisResult.moduleDescriptor ) - FileUtil.writeToFile(metaFile, KotlinJavascriptSerializationUtil.metadataAsString( + val serializedMetadata = KotlinJavascriptSerializationUtil.serializeMetadata( analysisResult.bindingContext, description, configuration.languageVersionSettings - )) + ) + FileUtil.writeToFile(metaFile, serializedMetadata.asString()) } finally { Disposer.dispose(rootDisposable) diff --git a/js/js.serializer/src/org/jetbrains/kotlin/serialization/js/KotlinJavascriptSerializationUtil.kt b/js/js.serializer/src/org/jetbrains/kotlin/serialization/js/KotlinJavascriptSerializationUtil.kt index 08046ab9ea6..268bb50fc3c 100644 --- a/js/js.serializer/src/org/jetbrains/kotlin/serialization/js/KotlinJavascriptSerializationUtil.kt +++ b/js/js.serializer/src/org/jetbrains/kotlin/serialization/js/KotlinJavascriptSerializationUtil.kt @@ -92,43 +92,88 @@ object KotlinJavascriptSerializationUtil { } fun serializeMetadata( - bindingContext: BindingContext, - module: ModuleDescriptor, - moduleKind: ModuleKind, - importedModules: List - ): JsProtoBuf.Library { - val builder = JsProtoBuf.Library.newBuilder() - - val moduleProtoKind = when (moduleKind) { - ModuleKind.PLAIN -> JsProtoBuf.Library.Kind.PLAIN - ModuleKind.AMD -> JsProtoBuf.Library.Kind.AMD - ModuleKind.COMMON_JS -> JsProtoBuf.Library.Kind.COMMON_JS - ModuleKind.UMD -> JsProtoBuf.Library.Kind.UMD - } - if (builder.kind != moduleProtoKind) { - builder.kind = moduleProtoKind - } - - importedModules.forEach { builder.addImportedModule(it) } + bindingContext: BindingContext, + jsDescriptor: JsModuleDescriptor, + languageVersionSettings: LanguageVersionSettings + ): SerializedMetadata { + val serializedFragments = HashMap() + val module = jsDescriptor.data for (fqName in getPackagesFqNames(module).sortedBy { it.asString() }) { val fragment = serializePackageFragment(bindingContext, module, fqName) + if (!fragment.isEmpty()) { - builder.addPackageFragment(fragment) + serializedFragments[fqName] = fragment } } - return builder.build() + return SerializedMetadata(serializedFragments, jsDescriptor, languageVersionSettings) } - fun metadataAsString( - bindingContext: BindingContext, - jsDescriptor: JsModuleDescriptor, - languageVersionSettings: LanguageVersionSettings - ): String = KotlinJavascriptMetadataUtils.formatMetadataAsString( - jsDescriptor.name, - jsDescriptor.serializeToBinaryMetadata(bindingContext, languageVersionSettings) - ) + class SerializedMetadata( + private val serializedFragments: Map, + private val jsDescriptor: JsModuleDescriptor, + private val languageVersionSettings: LanguageVersionSettings + ) { + fun asContentMap(): Map { + val contentMap = mutableMapOf() + + for ((fqName, part) in serializedFragments) { + val stream = ByteArrayOutputStream() + with(DataOutputStream(stream)) { + val version = JsMetadataVersion.INSTANCE.toArray() + writeInt(version.size) + version.forEach(this::writeInt) + } + + serializeHeader(jsDescriptor.data, fqName, languageVersionSettings).writeDelimitedTo(stream) + part.writeTo(stream) + + contentMap[JsSerializerProtocol.getKjsmFilePath(fqName)] = stream.toByteArray() + } + + return contentMap + } + + fun asString(): String = + KotlinJavascriptMetadataUtils.formatMetadataAsString(jsDescriptor.name, asByteArray()) + + private fun asByteArray(): ByteArray = + ByteArrayOutputStream().apply { + GZIPOutputStream(this).use { stream -> + serializeHeader( + jsDescriptor.data, + packageFqName = null, + languageVersionSettings = languageVersionSettings + ).writeDelimitedTo(stream) + asLibrary().writeTo(stream) + } + }.toByteArray() + + private fun asLibrary(): JsProtoBuf.Library { + val moduleKind = jsDescriptor.kind + jsDescriptor.imported + val builder = JsProtoBuf.Library.newBuilder() + + val moduleProtoKind = when (moduleKind) { + ModuleKind.PLAIN -> JsProtoBuf.Library.Kind.PLAIN + ModuleKind.AMD -> JsProtoBuf.Library.Kind.AMD + ModuleKind.COMMON_JS -> JsProtoBuf.Library.Kind.COMMON_JS + ModuleKind.UMD -> JsProtoBuf.Library.Kind.UMD + } + if (builder.kind != moduleProtoKind) { + builder.kind = moduleProtoKind + } + + jsDescriptor.imported.forEach { builder.addImportedModule(it) } + + for ((_, fragment) in serializedFragments.entries.sortedBy { (fqName, _) -> fqName.asString() }) { + builder.addPackageFragment(fragment) + } + + return builder.build() + } + } private fun serializePackageFragment(bindingContext: BindingContext, module: ModuleDescriptor, fqName: FqName): ProtoBuf.PackageFragment { val packageView = module.getPackage(fqName) @@ -211,33 +256,6 @@ object KotlinJavascriptSerializationUtil { return filesProto.build() } - fun toContentMap( - bindingContext: BindingContext, - module: ModuleDescriptor, - languageVersionSettings: LanguageVersionSettings - ): Map { - val contentMap = mutableMapOf() - - for (fqName in getPackagesFqNames(module)) { - val part = serializePackageFragment(bindingContext, module, fqName) - if (part.isEmpty()) continue - - val stream = ByteArrayOutputStream() - with(DataOutputStream(stream)) { - val version = JsMetadataVersion.INSTANCE.toArray() - writeInt(version.size) - version.forEach(this::writeInt) - } - - serializeHeader(module, fqName, languageVersionSettings).writeDelimitedTo(stream) - part.writeTo(stream) - - contentMap[JsSerializerProtocol.getKjsmFilePath(fqName)] = stream.toByteArray() - } - - return contentMap - } - private fun ProtoBuf.PackageFragment.isEmpty(): Boolean = class_Count == 0 && `package`.let { it.functionCount == 0 && it.propertyCount == 0 && it.typeAliasCount == 0 } @@ -293,18 +311,6 @@ object KotlinJavascriptSerializationUtil { } } - private fun JsModuleDescriptor.serializeToBinaryMetadata( - bindingContext: BindingContext, - languageVersionSettings: LanguageVersionSettings - ): ByteArray { - return ByteArrayOutputStream().apply { - GZIPOutputStream(this).use { stream -> - serializeHeader(data, null, languageVersionSettings).writeDelimitedTo(stream) - serializeMetadata(bindingContext, data, kind, imported).writeTo(stream) - } - }.toByteArray() - } - private fun ByteArray.deserializeToLibraryParts(name: String): JsModuleDescriptor { val (header, content) = GZIPInputStream(ByteArrayInputStream(this)).use { stream -> JsProtoBuf.Header.parseDelimitedFrom(stream, JsSerializerProtocol.extensionRegistry) to diff --git a/js/js.translator/src/org/jetbrains/kotlin/js/facade/TranslationResult.kt b/js/js.translator/src/org/jetbrains/kotlin/js/facade/TranslationResult.kt index b97f2dfde91..83958596814 100644 --- a/js/js.translator/src/org/jetbrains/kotlin/js/facade/TranslationResult.kt +++ b/js/js.translator/src/org/jetbrains/kotlin/js/facade/TranslationResult.kt @@ -108,12 +108,13 @@ abstract class TranslationResult protected constructor(val diagnostics: Diagnost imported = importedModules ) val settings = config.configuration.languageVersionSettings - val metaFileContent = KotlinJavascriptSerializationUtil.metadataAsString(bindingContext, moduleDescription, settings) + val serializedMetadata = KotlinJavascriptSerializationUtil.serializeMetadata(bindingContext, moduleDescription, settings) + val metaFileContent = serializedMetadata.asString() val sourceFilesForMetaFile = ArrayList(sourceFiles) val jsMetaFile = SimpleOutputFile(sourceFilesForMetaFile, metaFileName, metaFileContent) outputFiles.add(jsMetaFile) - KotlinJavascriptSerializationUtil.toContentMap(bindingContext, moduleDescriptor, settings).forEach { + serializedMetadata.asContentMap().forEach { // TODO Add correct source files outputFiles.add(SimpleOutputBinaryFile(emptyList(), config.moduleId + VfsUtilCore.VFS_SEPARATOR_CHAR + it.key, it.value)) }