diff --git a/js/js.serializer/src/org/jetbrains/kotlin/serialization/js/KotlinJavascriptAnnotationAndConstantLoader.kt b/js/js.serializer/src/org/jetbrains/kotlin/serialization/js/KotlinJavascriptAnnotationAndConstantLoader.kt new file mode 100644 index 00000000000..070281a8687 --- /dev/null +++ b/js/js.serializer/src/org/jetbrains/kotlin/serialization/js/KotlinJavascriptAnnotationAndConstantLoader.kt @@ -0,0 +1,74 @@ +/* + * Copyright 2010-2015 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.jetbrains.kotlin.serialization.js + +import org.jetbrains.kotlin.descriptors.ModuleDescriptor +import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptor +import org.jetbrains.kotlin.resolve.constants.CompileTimeConstant +import org.jetbrains.kotlin.serialization.ProtoBuf +import org.jetbrains.kotlin.serialization.deserialization.* +import org.jetbrains.kotlin.types.JetType + +class KotlinJavascriptAnnotationAndConstantLoader( + module: ModuleDescriptor +) : AnnotationAndConstantLoader> { + private val deserializer = AnnotationDeserializer(module) + + override fun loadClassAnnotations( + classProto: ProtoBuf.Class, + nameResolver: NameResolver + ): List { + val annotations = classProto.getExtension(JsProtoBuf.classAnnotation).orEmpty() + return annotations.map { proto -> deserializer.deserializeAnnotation(proto, nameResolver) } + } + + override fun loadCallableAnnotations( + container: ProtoContainer, + proto: ProtoBuf.Callable, + nameResolver: NameResolver, + kind: AnnotatedCallableKind + ): List { + val annotations = proto.getExtension(JsProtoBuf.callableAnnotation).orEmpty() + return annotations.map { proto -> deserializer.deserializeAnnotation(proto, nameResolver) } + } + + override fun loadValueParameterAnnotations( + container: ProtoContainer, + callable: ProtoBuf.Callable, + nameResolver: NameResolver, + kind: AnnotatedCallableKind, + proto: ProtoBuf.Callable.ValueParameter + ): List { + val annotations = proto.getExtension(JsProtoBuf.parameterAnnotation).orEmpty() + return annotations.map { proto -> deserializer.deserializeAnnotation(proto, nameResolver) } + } + + override fun loadTypeAnnotations(proto: ProtoBuf.Type, nameResolver: NameResolver): List { + // TODO: support type annotations for js descriptors + return listOf() + } + + override fun loadPropertyConstant( + container: ProtoContainer, + proto: ProtoBuf.Callable, + nameResolver: NameResolver, + expectedType: JetType + ): CompileTimeConstant<*>? { + val value = proto.getExtension(JsProtoBuf.compileTimeValue) + return deserializer.resolveValue(expectedType, value, nameResolver) + } +} diff --git a/js/js.serializer/src/org/jetbrains/kotlin/serialization/js/KotlinJavascriptPackageFragment.kt b/js/js.serializer/src/org/jetbrains/kotlin/serialization/js/KotlinJavascriptPackageFragment.kt new file mode 100644 index 00000000000..9f71c3f853e --- /dev/null +++ b/js/js.serializer/src/org/jetbrains/kotlin/serialization/js/KotlinJavascriptPackageFragment.kt @@ -0,0 +1,39 @@ +/* + * Copyright 2010-2015 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.jetbrains.kotlin.serialization.js + +import org.jetbrains.kotlin.serialization.deserialization.DeserializedPackageFragment +import org.jetbrains.kotlin.descriptors.ModuleDescriptor +import org.jetbrains.kotlin.name.FqName +import org.jetbrains.kotlin.name.Name +import org.jetbrains.kotlin.serialization.ProtoBuf +import org.jetbrains.kotlin.storage.StorageManager +import java.io.InputStream + +public class KotlinJavascriptPackageFragment( + fqName: FqName, + storageManager: StorageManager, + module: ModuleDescriptor, + loadResource: (path: String) -> InputStream? +) : DeserializedPackageFragment(fqName, storageManager, module, KotlinJavascriptSerializedResourcePaths, loadResource) { + + protected override fun loadClassNames(fqName: FqName, packageProto: ProtoBuf.Package): Collection { + val classesStream = loadResourceSure(KotlinJavascriptSerializedResourcePaths.getClassesInPackageFilePath(fqName)) + val classesProto = JsProtoBuf.Classes.parseFrom(classesStream, serializedResourcePaths.EXTENSION_REGISTRY) + return classesProto.getClassNameList()?.map { id -> nameResolver.getName(id) } ?: listOf() + } +} 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 3edf6fb7688..d5247920989 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 @@ -17,12 +17,7 @@ package org.jetbrains.kotlin.serialization.js import com.google.protobuf.ByteString -import org.jetbrains.kotlin.builtins.BuiltInsSerializationUtil -import org.jetbrains.kotlin.builtins.createBuiltInPackageFragmentProvider -import org.jetbrains.kotlin.descriptors.ClassDescriptor -import org.jetbrains.kotlin.descriptors.DeclarationDescriptor -import org.jetbrains.kotlin.descriptors.ModuleDescriptor -import org.jetbrains.kotlin.descriptors.PackageFragmentProvider +import org.jetbrains.kotlin.descriptors.* import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.resolve.DescriptorUtils import org.jetbrains.kotlin.resolve.descriptorUtil.classId @@ -30,7 +25,7 @@ import org.jetbrains.kotlin.resolve.scopes.DescriptorKindFilter import org.jetbrains.kotlin.serialization.DescriptorSerializer import org.jetbrains.kotlin.serialization.ProtoBuf import org.jetbrains.kotlin.serialization.SerializationUtil -import org.jetbrains.kotlin.serialization.builtins.BuiltInsSerializerExtension +import org.jetbrains.kotlin.serialization.StringTable import org.jetbrains.kotlin.serialization.deserialization.FlexibleTypeCapabilitiesDeserializer import org.jetbrains.kotlin.storage.StorageManager import org.jetbrains.kotlin.utils.KotlinJavascriptMetadataUtils @@ -41,28 +36,51 @@ import java.util.zip.GZIPOutputStream import kotlin.platform.platformStatic public object KotlinJavascriptSerializationUtil { - private val PACKAGE_FILE_EXT = ".kotlin_package" + public val CLASS_METADATA_FILE_EXTENSION: String = "kjsm" + + private val PACKAGE_DEFAULT_BYTES = run { + val stream = ByteArrayOutputStream() + ProtoBuf.Package.getDefaultInstance().writeTo(stream) + stream.toByteArray() + } + + private val CLASSES_IN_PACKAGE_DEFAULT_BYTES = run { + val stream = ByteArrayOutputStream() + JsProtoBuf.Classes.getDefaultInstance().writeTo(stream) + stream.toByteArray() + } + + private val STRING_TABLE_DEFAULT_BYTES = run { + val nameStream = ByteArrayOutputStream() + val strings = StringTable(KotlinJavascriptSerializerExtension) + SerializationUtil.serializeStringTable(nameStream, strings.serializeSimpleNames(), strings.serializeQualifiedNames()) + nameStream.toByteArray() + } platformStatic public fun createPackageFragmentProvider(moduleDescriptor: ModuleDescriptor, metadata: ByteArray, storageManager: StorageManager): PackageFragmentProvider? { - val gzipInputStream = GZIPInputStream(ByteArrayInputStream(metadata)) - val content = JsProtoBuf.Library.parseFrom(gzipInputStream) - gzipInputStream.close() - - val contentMap: MutableMap = hashMapOf() - for (index in content.getEntryCount().indices) { - val entry = content.getEntry(index) - contentMap[entry.getPath()] = entry.getContent().toByteArray() - } + val contentMap = metadata.toContentMap() val packageFqNames = getPackages(contentMap).map { FqName(it) }.toSet() if (packageFqNames.isEmpty()) return null - return createBuiltInPackageFragmentProvider( + return createKotlinJavascriptPackageFragmentProvider( storageManager, moduleDescriptor, packageFqNames, FlexibleTypeCapabilitiesDeserializer.Dynamic ) { path -> - if (!contentMap.containsKey(path)) null else ByteArrayInputStream(contentMap.get(path)) + if (!contentMap.containsKey(path)) { + when { + KotlinJavascriptSerializedResourcePaths.isPackageMetadataFile(path) -> + ByteArrayInputStream(PACKAGE_DEFAULT_BYTES) + KotlinJavascriptSerializedResourcePaths.isStringTableFile(path) -> + ByteArrayInputStream(STRING_TABLE_DEFAULT_BYTES) + KotlinJavascriptSerializedResourcePaths.isClassesInPackageFile(path) -> + ByteArrayInputStream(CLASSES_IN_PACKAGE_DEFAULT_BYTES) + else -> + null + } + } + else ByteArrayInputStream(contentMap.get(path)) } } @@ -81,27 +99,15 @@ public object KotlinJavascriptSerializationUtil { return byteStream.toByteArray() } - public fun metadataAsString(moduleName: String, moduleDescriptor: ModuleDescriptor): String { - val contentMap = hashMapOf() - - DescriptorUtils.getPackagesFqNames(moduleDescriptor).forEach { - fqName -> - serializePackage(moduleDescriptor, fqName) { - fileName, stream -> - contentMap[fileName] = stream.toByteArray() - } - } - - val content = KotlinJavascriptSerializationUtil.contentMapToByteArray(contentMap) - return KotlinJavascriptMetadataUtils.formatMetadataAsString(moduleName, content) - } + public fun metadataAsString(moduleName: String, moduleDescriptor: ModuleDescriptor): String = + KotlinJavascriptMetadataUtils.formatMetadataAsString(moduleName, moduleDescriptor.toBinaryMetadata()) fun serializePackage(module: ModuleDescriptor, fqName: FqName, writeFun: (String, ByteArrayOutputStream) -> Unit) { val packageView = module.getPackage(fqName) ?: error("No package resolved in $module") val skip: (DeclarationDescriptor) -> Boolean = { DescriptorUtils.getContainingModule(it) != module } - val serializer = DescriptorSerializer.createTopLevel(BuiltInsSerializerExtension) + val serializer = DescriptorSerializer.createTopLevel(KotlinJavascriptSerializerExtension) val classifierDescriptors = DescriptorSerializer.sort(packageView.getMemberScope().getDescriptors(DescriptorKindFilter.CLASSIFIERS)) @@ -116,23 +122,95 @@ public object KotlinJavascriptSerializationUtil { val packageStream = ByteArrayOutputStream() val fragments = module.getPackageFragmentProvider().getPackageFragments(fqName) val packageProto = serializer.packageProto(fragments, skip).build() ?: error("Package fragments not serialized: $fragments") - packageProto.writeTo(packageStream) - writeFun(BuiltInsSerializationUtil.getPackageFilePath(fqName), packageStream) + if (packageProto.getMemberCount() > 0) { + packageProto.writeTo(packageStream) + writeFun(KotlinJavascriptSerializedResourcePaths.getPackageFilePath(fqName), packageStream) + } val nameStream = ByteArrayOutputStream() val strings = serializer.getStringTable() - SerializationUtil.serializeStringTable(nameStream, strings.serializeSimpleNames(), strings.serializeQualifiedNames()) - writeFun(BuiltInsSerializationUtil.getStringTableFilePath(fqName), nameStream) + + serializeClassNamesInPackage(fqName, fragments, strings, skip, writeFun) + + val simpleNames = strings.serializeSimpleNames() + val qualifiedNames = strings.serializeQualifiedNames() + + if (simpleNames.getStringCount() > 0 || qualifiedNames.getQualifiedNameCount() > 0) { + SerializationUtil.serializeStringTable(nameStream, simpleNames, qualifiedNames) + writeFun(KotlinJavascriptSerializedResourcePaths.getStringTableFilePath(fqName), nameStream) + } } - fun getFileName(classDescriptor: ClassDescriptor): String { - return BuiltInsSerializationUtil.getClassMetadataPath(classDescriptor.classId) + private fun serializeClassNamesInPackage( + fqName: FqName, + packageFragments: Collection, + stringTable: StringTable, + skip: (DeclarationDescriptor) -> Boolean, + writeFun: (String, ByteArrayOutputStream) -> Unit + ) { + val classes = packageFragments.flatMap { + it.getMemberScope().getDescriptors(DescriptorKindFilter.CLASSIFIERS).filterIsInstance() + }.filter { !skip(it) } + + val builder = JsProtoBuf.Classes.newBuilder() + + for (descriptor in DescriptorSerializer.sort(classes)) { + builder.addClassName(stringTable.getSimpleNameIndex(descriptor.getName())) + } + + val classesProto = builder.build() + + if (classesProto.getClassNameCount() > 0) { + val stream = ByteArrayOutputStream() + classesProto.writeTo(stream) + writeFun(KotlinJavascriptSerializedResourcePaths.getClassesInPackageFilePath(fqName), stream) + } } - private fun getPackageName(filePath: String): String { - return filePath.substringBeforeLast('/').replace('/', '.') + private fun getFileName(classDescriptor: ClassDescriptor): String { + return KotlinJavascriptSerializedResourcePaths.getClassMetadataPath(classDescriptor.classId) } - private fun getPackages(contentMap: Map): List = - contentMap.keySet().filter { it.endsWith(PACKAGE_FILE_EXT) }.map { getPackageName(it) } -} \ No newline at end of file + private fun ByteArray.toContentMap(): Map { + val gzipInputStream = GZIPInputStream(ByteArrayInputStream(this)) + val content = JsProtoBuf.Library.parseFrom(gzipInputStream) + gzipInputStream.close() + + val contentMap: MutableMap = hashMapOf() + content.getEntryList().forEach { entry -> contentMap[entry.getPath()] = entry.getContent().toByteArray() } + + return contentMap + } + + private fun ModuleDescriptor.toContentMap(): Map { + val contentMap = hashMapOf() + + DescriptorUtils.getPackagesFqNames(this).forEach { + serializePackage(this, it) { + fileName, stream -> contentMap[fileName] = stream.toByteArray() + } + } + + return contentMap + } + + private fun getPackages(contentMap: Map): Set { + val keys = contentMap.keySet().map { (if (it.startsWith('/')) it else "/" + it).substringBeforeLast('/') }.toSet() + + val result = hashSetOf() + + fun addNames(name: String) { + result.add(name) + if (name != "") { + addNames(name.substringBeforeLast('/')) + } + } + + keys.forEach { addNames(it) } + + return result.map { it.substringAfter('/').replace('/', '.') }.toSet() + } + + private fun ModuleDescriptor.toBinaryMetadata(): ByteArray = + KotlinJavascriptSerializationUtil.contentMapToByteArray(this.toContentMap()) +} diff --git a/js/js.serializer/src/org/jetbrains/kotlin/serialization/js/KotlinJavascriptSerializedResourcePaths.kt b/js/js.serializer/src/org/jetbrains/kotlin/serialization/js/KotlinJavascriptSerializedResourcePaths.kt new file mode 100644 index 00000000000..61f3144540a --- /dev/null +++ b/js/js.serializer/src/org/jetbrains/kotlin/serialization/js/KotlinJavascriptSerializedResourcePaths.kt @@ -0,0 +1,86 @@ +/* + * Copyright 2010-2015 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.jetbrains.kotlin.serialization.js + +import com.google.protobuf.ExtensionRegistryLite +import org.jetbrains.kotlin.name.ClassId +import org.jetbrains.kotlin.name.FqName +import org.jetbrains.kotlin.name.Name +import org.jetbrains.kotlin.serialization.SerializedResourcePaths + +public object KotlinJavascriptSerializedResourcePaths : SerializedResourcePaths() { + public override val EXTENSION_REGISTRY: ExtensionRegistryLite + + init { + EXTENSION_REGISTRY = ExtensionRegistryLite.newInstance() + JsProtoBuf.registerAllExtensions(EXTENSION_REGISTRY) + } + + private val CLASSES_FILE_EXTENSION = "kotlin_classes" + private val STRING_TABLE_FILE_EXTENSION = "kotlin_string_table" + + private val PACKAGE_CLASS_NAME_SUFFIX: String = "Package" + private val DEFAULT_PACKAGE_CLASS_NAME: String = "_Default" + PACKAGE_CLASS_NAME_SUFFIX + + public fun getClassesInPackageFilePath(fqName: FqName): String = + fqName.toPath().withSepIfNotEmpty() + shortName(fqName) + "." + CLASSES_FILE_EXTENSION + + + public override fun getClassMetadataPath(classId: ClassId): String { + return classId.getPackageFqName().toPath().withSepIfNotEmpty() + classId.getRelativeClassName().asString() + + "." + KotlinJavascriptSerializationUtil.CLASS_METADATA_FILE_EXTENSION + } + + public override fun getPackageFilePath(fqName: FqName): String = + getPackageClassFqName(fqName).toPath() + "." + KotlinJavascriptSerializationUtil.CLASS_METADATA_FILE_EXTENSION + + public override fun getStringTableFilePath(fqName: FqName): String = + fqName.toPath().withSepIfNotEmpty() + shortName(fqName) + "." + STRING_TABLE_FILE_EXTENSION + + public fun isPackageMetadataFile(fileName: String): Boolean = + KotlinJavascriptSerializedResourcePaths.getPackageFilePath(getPackageFqName(fileName)) == fileName + + public fun isStringTableFile(fileName: String): Boolean = + KotlinJavascriptSerializedResourcePaths.getStringTableFilePath(getPackageFqName(fileName)) == fileName + + public fun isClassesInPackageFile(fileName: String): Boolean = + KotlinJavascriptSerializedResourcePaths.getClassesInPackageFilePath(getPackageFqName(fileName)) == fileName + + private fun getPackageFqName(fileName: String): FqName = FqName(getPackageName(fileName)) + + private fun getPackageName(filePath: String): String = + if (filePath.indexOf('/') >= 0) filePath.substringBeforeLast('/').replace('/', '.') else "" + + private fun FqName.toPath() = this.asString().replace('.', '/') + + private fun String.withSepIfNotEmpty() = if (this.isEmpty()) this else this + "/" + + private fun shortName(fqName: FqName): String = + if (fqName.isRoot()) "default-package" else fqName.shortName().asString() + + private fun getPackageClassFqName(packageFQN: FqName): FqName { + return packageFQN.child(Name.identifier(getPackageClassName(packageFQN))) + } + + private fun getPackageClassName(packageFQN: FqName): String { + return if (packageFQN.isRoot()) DEFAULT_PACKAGE_CLASS_NAME else capitalizeNonEmptyString(packageFQN.shortName().asString()) + PACKAGE_CLASS_NAME_SUFFIX + } + + private fun capitalizeNonEmptyString(s: String): String { + return if (Character.isUpperCase(s.charAt(0))) s else Character.toUpperCase(s.charAt(0)) + s.substring(1) + } +} \ No newline at end of file diff --git a/js/js.serializer/src/org/jetbrains/kotlin/serialization/js/KotlinJavascriptSerializerExtension.kt b/js/js.serializer/src/org/jetbrains/kotlin/serialization/js/KotlinJavascriptSerializerExtension.kt new file mode 100644 index 00000000000..d2baa935376 --- /dev/null +++ b/js/js.serializer/src/org/jetbrains/kotlin/serialization/js/KotlinJavascriptSerializerExtension.kt @@ -0,0 +1,57 @@ +/* + * Copyright 2010-2015 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.jetbrains.kotlin.serialization.js + +import org.jetbrains.kotlin.descriptors.* +import org.jetbrains.kotlin.resolve.constants.NullValue +import org.jetbrains.kotlin.resolve.descriptorUtil.builtIns +import org.jetbrains.kotlin.resolve.scopes.DescriptorKindFilter +import org.jetbrains.kotlin.serialization.* + +public object KotlinJavascriptSerializerExtension : SerializerExtension() { + override fun serializeClass(descriptor: ClassDescriptor, proto: ProtoBuf.Class.Builder, stringTable: StringTable) { + for (annotation in descriptor.getAnnotations()) { + proto.addExtension(JsProtoBuf.classAnnotation, AnnotationSerializer.serializeAnnotation(annotation, stringTable)) + } + } + + override fun serializeCallable( + callable: CallableMemberDescriptor, + proto: ProtoBuf.Callable.Builder, + stringTable: StringTable + ) { + for (annotation in callable.getAnnotations()) { + proto.addExtension(JsProtoBuf.callableAnnotation, AnnotationSerializer.serializeAnnotation(annotation, stringTable)) + } + val propertyDescriptor = callable as? PropertyDescriptor ?: return + val compileTimeConstant = propertyDescriptor.getCompileTimeInitializer() + if (compileTimeConstant != null && compileTimeConstant !is NullValue) { + val type = compileTimeConstant.getType(propertyDescriptor.builtIns) + proto.setExtension(JsProtoBuf.compileTimeValue, AnnotationSerializer.valueProto(compileTimeConstant, type, stringTable).build()) + } + } + + override fun serializeValueParameter( + descriptor: ValueParameterDescriptor, + proto: ProtoBuf.Callable.ValueParameter.Builder, + stringTable: StringTable + ) { + for (annotation in descriptor.getAnnotations()) { + proto.addExtension(JsProtoBuf.parameterAnnotation, AnnotationSerializer.serializeAnnotation(annotation, stringTable)) + } + } +} \ No newline at end of file diff --git a/js/js.serializer/src/org/jetbrains/kotlin/serialization/js/kotlinJavascriptPackageFragmentProvider.kt b/js/js.serializer/src/org/jetbrains/kotlin/serialization/js/kotlinJavascriptPackageFragmentProvider.kt new file mode 100644 index 00000000000..cf2f9ac3cbb --- /dev/null +++ b/js/js.serializer/src/org/jetbrains/kotlin/serialization/js/kotlinJavascriptPackageFragmentProvider.kt @@ -0,0 +1,61 @@ +/* + * Copyright 2010-2015 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.jetbrains.kotlin.serialization.js + +import org.jetbrains.kotlin.serialization.deserialization.ResourceLoadingClassDataFinder +import org.jetbrains.kotlin.descriptors.ModuleDescriptor +import org.jetbrains.kotlin.descriptors.PackageFragmentProvider +import org.jetbrains.kotlin.descriptors.PackageFragmentProviderImpl +import org.jetbrains.kotlin.name.FqName +import org.jetbrains.kotlin.serialization.deserialization.DeserializationComponents +import org.jetbrains.kotlin.serialization.deserialization.FlexibleTypeCapabilitiesDeserializer +import org.jetbrains.kotlin.serialization.deserialization.LocalClassResolverImpl +import org.jetbrains.kotlin.storage.StorageManager +import java.io.InputStream + +public fun createKotlinJavascriptPackageFragmentProvider( + storageManager: StorageManager, + module: ModuleDescriptor, + packageFqNames: Set, + flexibleTypeCapabilitiesDeserializer: FlexibleTypeCapabilitiesDeserializer, + loadResource: (String) -> InputStream? +): PackageFragmentProvider { + val packageFragments = packageFqNames.map { fqName -> + KotlinJavascriptPackageFragment(fqName, storageManager, module, loadResource) + } + val provider = PackageFragmentProviderImpl(packageFragments) + + val localClassResolver = LocalClassResolverImpl() + + val components = DeserializationComponents( + storageManager, + module, + ResourceLoadingClassDataFinder(provider, KotlinJavascriptSerializedResourcePaths, loadResource), + KotlinJavascriptAnnotationAndConstantLoader(module), + provider, + localClassResolver, + flexibleTypeCapabilitiesDeserializer + ) + + localClassResolver.setDeserializationComponents(components) + + for (packageFragment in packageFragments) { + packageFragment.setDeserializationComponents(components) + } + + return provider +}