fun generateDeclarationExport()

in compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/jsexport/ExportModelToJsStatements.kt [48:215]


    fun generateDeclarationExport(
        declaration: ExportedDeclaration,
        namespace: JsExpression?,
        esModules: Boolean,
        parentClass: IrClass? = null,
    ): List<JsStatement> {
        return when (declaration) {
            is ExportedNamespace -> {
                require(namespace != null) { "Only namespaced namespaces are allowed" }

                val namespaceVariableName = JsName(declaration.name, true)
                val namespaceRef = jsElementAccess(declaration.name, namespace)
                val namespaceDeclaration = JsVars(
                    JsVars.Variant.Var,
                    JsVars.JsVar(
                        namespaceVariableName,
                        JsAstUtils.or(
                            namespaceRef,
                            jsAssignment(
                                namespaceRef,
                                JsObjectLiteral()
                            )
                        )
                    )
                )

                listOf(namespaceDeclaration) + declaration.declarations.flatMap {
                    generateDeclarationExport(
                        it,
                        namespaceVariableName.makeRef(),
                        esModules
                    )
                }
            }

            is ExportedFunction -> {
                val name = staticContext.getNameForStaticDeclaration(declaration.ir)
                when {
                    namespace != null ->
                        listOf(jsAssignment(jsElementAccess(declaration.name, namespace), JsNameRef(name)).makeStmt())

                    esModules -> {
                        if (declaration.attributes.contains(ExportedAttribute.DefaultExport)) {
                            listOf(JsExport(JsExport.Subject.Default(name.makeRef())))
                        } else {
                            listOf(JsExport(name.makeRef(), alias = JsName(declaration.name, false)))
                        }
                    }
                    else -> emptyList()
                }
            }

            is ExportedProperty -> {
                require(namespace != null || esModules) { "Only namespaced properties are allowed" }
                when {
                    namespace == null -> {
                        val property = declaration.generateTopLevelGetters()
                        val exportStatement = if (declaration.attributes.contains(ExportedAttribute.DefaultExport)) {
                            JsExport(JsExport.Subject.Default(property.name.makeRef()))
                        } else {
                            JsExport(property.name.makeRef(), JsName(declaration.name, false))
                        }

                        listOf(JsVars(JsVars.Variant.Var, property), exportStatement)
                    }
                    declaration.isDefaultImplementation -> {
                        val property = declaration.generateTopLevelGetters()
                        listOf(
                            JsVars(JsVars.Variant.Var, property),
                            jsAssignment(jsElementAccess(declaration.name, namespace), property.name.makeRef()).makeStmt()
                        )
                    }
                    else -> {
                        val getter = declaration.irGetter?.let { staticContext.getNameForStaticDeclaration(it) }
                        val setter = declaration.irSetter?.let { staticContext.getNameForStaticDeclaration(it) }
                        listOf(
                            defineProperty(
                                namespace,
                                declaration.name,
                                getter?.makeRef(),
                                setter?.makeRef(),
                                staticContext,
                                enumerable = true
                            ).makeStmt()
                        )
                    }
                }
            }

            is ExportedObject -> {
                require(namespace != null || esModules) { "Only namespaced properties are allowed" }
                val (name, objectClassInitialization) = declaration.getNameAndInitialization()
                val newNameSpace = jsElementAccess(Namer.PROTOTYPE_NAME, name.makeRef())
                val staticsExport =
                    declaration.nestedClasses.flatMap { generateDeclarationExport(it, newNameSpace, esModules, declaration.ir) }

                val objectExport = when {
                    es6mode || namespace == null -> generateDeclarationExport(
                        ExportedProperty(
                            declaration.name,
                            isStatic = parentClass?.isObject != true,
                            irGetter = declaration.irGetter,
                        ).apply { attributes.addAll(declaration.attributes) },
                        namespace,
                        esModules,
                        parentClass
                    )
                    else -> listOf(
                        defineProperty(
                            namespace,
                            declaration.name,
                            staticContext.getNameForStaticDeclaration(
                                declaration.irGetter
                                    ?: irError("Expect to have an object getter in its export model") {
                                        withIrEntry("declaration.ir", declaration.ir)
                                    }
                            ).makeRef(),
                            null,
                            staticContext,
                            enumerable = true
                        ).makeStmt()
                    )
                }

                listOfNotNull(objectClassInitialization.takeIf { staticsExport.isNotEmpty() }) + objectExport + staticsExport
            }

            is ExportedRegularClass -> {
                // These are used when @JsStatic is used or exporting secondary constructors annotated with @JsName
                val staticMembers = declaration.members
                    .filter { it is ExportedNamespace || it is ExportedFunction && it.isStatic && !it.ir.isEs6ConstructorReplacement }
                    .takeIf { !declaration.ir.isInner }.orEmpty()

                if (!allowImplementingInterfaces && declaration.isInterface && staticMembers.isEmpty() && declaration.nestedClasses.isEmpty()) {
                    return emptyList()
                }

                val (name, classInitialization) = declaration.getNameAndInitialization()
                val newNameSpace = when {
                    namespace != null -> jsElementAccess(declaration.name, namespace)
                    esModules -> name.makeRef()
                    else -> prototypeOf(name.makeRef(), staticContext)
                }
                val klassExport = when {
                    namespace != null -> jsAssignment(newNameSpace, name.makeRef()).makeStmt()
                    esModules -> {
                        if (declaration.attributes.contains(ExportedAttribute.DefaultExport)) {
                            JsExport(JsExport.Subject.Default(name.makeRef()))
                        } else {
                            JsExport(name.makeRef(), JsName(declaration.name, false))
                        }
                    }
                    else -> null
                }

                val enumEntries = declaration.members.filter { it is ExportedProperty && it.isStatic }

                val innerClassesAssignments = declaration.nestedClasses
                    .filter { it.ir.isInner }
                    .map { it.generateInnerClassAssignment(name) }

                val staticsExport = (staticMembers + enumEntries + declaration.nestedClasses)
                    .flatMap { generateDeclarationExport(it, newNameSpace, esModules, declaration.ir) }

                listOfNotNull(classInitialization, klassExport) + staticsExport + innerClassesAssignments
            }
        }
    }