[K/JS] Import @JsModule declarations without asterisk
This commit is contained in:
+3
-3
@@ -223,7 +223,7 @@ class IrModuleToJsTransformer(
|
|||||||
private val optimizeGeneratedJs = backendContext.configuration.get(JSConfigurationKeys.OPTIMIZE_GENERATED_JS, true)
|
private val optimizeGeneratedJs = backendContext.configuration.get(JSConfigurationKeys.OPTIMIZE_GENERATED_JS, true)
|
||||||
|
|
||||||
private fun generateProgramFragment(fileExports: IrFileExports, minimizedMemberNames: Boolean): JsIrProgramFragment {
|
private fun generateProgramFragment(fileExports: IrFileExports, minimizedMemberNames: Boolean): JsIrProgramFragment {
|
||||||
val nameGenerator = JsNameLinkingNamer(backendContext, minimizedMemberNames)
|
val nameGenerator = JsNameLinkingNamer(backendContext, minimizedMemberNames, isEsModules)
|
||||||
|
|
||||||
val globalNameScope = NameTable<IrDeclaration>()
|
val globalNameScope = NameTable<IrDeclaration>()
|
||||||
|
|
||||||
@@ -329,9 +329,9 @@ class IrModuleToJsTransformer(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
nameGenerator.imports.entries.forEach { (declaration, importExpression) ->
|
nameGenerator.imports.entries.forEach { (declaration, importStatement) ->
|
||||||
val tag = computeTag(declaration) ?: error("No tag for imported declaration ${declaration.render()}")
|
val tag = computeTag(declaration) ?: error("No tag for imported declaration ${declaration.render()}")
|
||||||
result.imports[tag] = importExpression
|
result.imports[tag] = importStatement
|
||||||
result.optionalCrossModuleImports += tag
|
result.optionalCrossModuleImports += tag
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -17,7 +17,7 @@ class JsIrProgramFragment(val packageFqn: String) {
|
|||||||
val declarations = JsCompositeBlock()
|
val declarations = JsCompositeBlock()
|
||||||
val exports = JsCompositeBlock()
|
val exports = JsCompositeBlock()
|
||||||
val importedModules = mutableListOf<JsImportedModule>()
|
val importedModules = mutableListOf<JsImportedModule>()
|
||||||
val imports = mutableMapOf<String, JsExpression>()
|
val imports = mutableMapOf<String, JsStatement>()
|
||||||
var dts: TypeScriptFragment? = null
|
var dts: TypeScriptFragment? = null
|
||||||
val classes = mutableMapOf<JsName, JsIrIcClassModel>()
|
val classes = mutableMapOf<JsName, JsIrIcClassModel>()
|
||||||
val initializers = JsCompositeBlock()
|
val initializers = JsCompositeBlock()
|
||||||
|
|||||||
+74
-37
@@ -19,7 +19,11 @@ import org.jetbrains.kotlin.js.backend.ast.*
|
|||||||
import org.jetbrains.kotlin.utils.DFS
|
import org.jetbrains.kotlin.utils.DFS
|
||||||
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
|
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
|
||||||
|
|
||||||
class JsNameLinkingNamer(private val context: JsIrBackendContext, private val minimizedMemberNames: Boolean) : IrNamerBase() {
|
class JsNameLinkingNamer(
|
||||||
|
private val context: JsIrBackendContext,
|
||||||
|
private val minimizedMemberNames: Boolean,
|
||||||
|
private val isEsModules: Boolean
|
||||||
|
) : IrNamerBase() {
|
||||||
|
|
||||||
val nameMap = mutableMapOf<IrDeclaration, JsName>()
|
val nameMap = mutableMapOf<IrDeclaration, JsName>()
|
||||||
|
|
||||||
@@ -33,50 +37,19 @@ class JsNameLinkingNamer(private val context: JsIrBackendContext, private val mi
|
|||||||
}
|
}
|
||||||
|
|
||||||
val importedModules = mutableListOf<JsImportedModule>()
|
val importedModules = mutableListOf<JsImportedModule>()
|
||||||
val imports = mutableMapOf<IrDeclaration, JsExpression>()
|
val imports = mutableMapOf<IrDeclaration, JsStatement>()
|
||||||
|
|
||||||
override fun getNameForStaticDeclaration(declaration: IrDeclarationWithName): JsName {
|
override fun getNameForStaticDeclaration(declaration: IrDeclarationWithName): JsName {
|
||||||
|
|
||||||
if (declaration.isEffectivelyExternal()) {
|
if (declaration.isEffectivelyExternal()) {
|
||||||
val jsModule: String? = declaration.getJsModule()
|
val jsModule: String? = declaration.getJsModule()
|
||||||
val maybeParentFile: IrFile? = declaration.parent as? IrFile
|
val maybeParentFile: IrFile? = declaration.parent as? IrFile
|
||||||
val fileJsModule: String? = maybeParentFile?.getJsModule()
|
val fileJsModule: String? = maybeParentFile?.getJsModule()
|
||||||
val jsQualifier: List<JsName>? = maybeParentFile?.getJsQualifier()?.split('.')?.map { JsName(it, false) }
|
val jsQualifier: List<JsName>? = maybeParentFile?.getJsQualifier()?.split('.')?.map { JsName(it, false) }
|
||||||
|
|
||||||
when {
|
return when {
|
||||||
jsModule != null -> {
|
jsModule != null -> declaration.generateImportForDeclarationWithJsModule(jsModule)
|
||||||
val nameString = if (declaration.isJsNonModule()) {
|
fileJsModule != null -> declaration.generateImportForDeclarationInFileWithJsModule(fileJsModule, jsQualifier)
|
||||||
declaration.getJsNameOrKotlinName().asString()
|
else -> declaration.generateRegularQualifiedImport(jsQualifier)
|
||||||
} else {
|
|
||||||
val parent = declaration.fqNameWhenAvailable!!.parent()
|
|
||||||
parent.child(declaration.getJsNameOrKotlinName()).asString()
|
|
||||||
}
|
|
||||||
val name = JsName(sanitizeName(nameString), false)
|
|
||||||
importedModules += JsImportedModule(jsModule, name, name.makeRef())
|
|
||||||
return name
|
|
||||||
}
|
|
||||||
|
|
||||||
fileJsModule != null -> {
|
|
||||||
if (declaration !in nameMap) {
|
|
||||||
val moduleName = JsName(sanitizeName("\$module\$$fileJsModule"), true)
|
|
||||||
importedModules += JsImportedModule(fileJsModule, moduleName, null)
|
|
||||||
val qualifiedReference =
|
|
||||||
if (jsQualifier == null) moduleName.makeRef() else (listOf(moduleName) + jsQualifier).makeRef()
|
|
||||||
imports[declaration] = jsElementAccess(declaration.getJsNameOrKotlinName().identifier, qualifiedReference)
|
|
||||||
return declaration.getName()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
else -> {
|
|
||||||
val name = declaration.getJsNameOrKotlinName().identifier
|
|
||||||
|
|
||||||
if (jsQualifier != null) {
|
|
||||||
imports[declaration] = jsElementAccess(name, jsQualifier.makeRef())
|
|
||||||
return declaration.getName()
|
|
||||||
}
|
|
||||||
|
|
||||||
return name.toJsName(temporary = false)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -104,6 +77,70 @@ class JsNameLinkingNamer(private val context: JsIrBackendContext, private val mi
|
|||||||
return JsName(field.parentAsClass.fieldData()[field]!!, false)
|
return JsName(field.parentAsClass.fieldData()[field]!!, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun IrDeclarationWithName.generateImportForDeclarationWithJsModule(jsModule: String): JsName {
|
||||||
|
val nameString = if (isJsNonModule()) {
|
||||||
|
getJsNameOrKotlinName().asString()
|
||||||
|
} else {
|
||||||
|
val parent = fqNameWhenAvailable!!.parent()
|
||||||
|
parent.child(getJsNameOrKotlinName()).asString()
|
||||||
|
}
|
||||||
|
val name = JsName(sanitizeName(nameString), true)
|
||||||
|
|
||||||
|
if (isEsModules) {
|
||||||
|
imports[this] = JsImport(jsModule, JsImport.Target.Default(name.makeRef()))
|
||||||
|
} else {
|
||||||
|
importedModules += JsImportedModule(jsModule, name, name.makeRef())
|
||||||
|
}
|
||||||
|
return name
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun IrDeclarationWithName.generateImportForDeclarationInFileWithJsModule(
|
||||||
|
fileJsModule: String,
|
||||||
|
jsQualifier: List<JsName>?
|
||||||
|
): JsName {
|
||||||
|
if (this in nameMap) return getName()
|
||||||
|
|
||||||
|
val declarationStableName = getJsNameOrKotlinName().identifier
|
||||||
|
|
||||||
|
if (isEsModules) {
|
||||||
|
val importedName = jsQualifier?.firstOrNull() ?: declarationStableName.toJsName(temporary = false)
|
||||||
|
val importStatement = JsImport(fileJsModule, JsImport.Element(importedName))
|
||||||
|
imports[this] = when (val qualifiedReference = jsQualifier?.makeRef()) {
|
||||||
|
null -> importStatement
|
||||||
|
else -> JsCompositeBlock(
|
||||||
|
listOf(
|
||||||
|
importStatement,
|
||||||
|
jsElementAccess(declarationStableName, qualifiedReference).putIntoVariableWitName(
|
||||||
|
declarationStableName.toJsName()
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
val moduleName = JsName(sanitizeName("\$module\$$fileJsModule"), true)
|
||||||
|
importedModules += JsImportedModule(fileJsModule, moduleName, null)
|
||||||
|
val qualifiedReference =
|
||||||
|
if (jsQualifier == null) moduleName.makeRef() else (listOf(moduleName) + jsQualifier).makeRef()
|
||||||
|
imports[this] =
|
||||||
|
jsElementAccess(declarationStableName, qualifiedReference).putIntoVariableWitName(declarationStableName.toJsName())
|
||||||
|
}
|
||||||
|
|
||||||
|
return getName()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun IrDeclarationWithName.generateRegularQualifiedImport(jsQualifier: List<JsName>?): JsName {
|
||||||
|
val name = getJsNameOrKotlinName().identifier
|
||||||
|
|
||||||
|
if (jsQualifier != null) {
|
||||||
|
imports[this] = jsElementAccess(name, jsQualifier.makeRef()).putIntoVariableWitName(name.toJsName())
|
||||||
|
return getName()
|
||||||
|
}
|
||||||
|
|
||||||
|
return name.toJsName(temporary = false)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
private fun IrClass.fieldData(): Map<IrField, String> {
|
private fun IrClass.fieldData(): Map<IrField, String> {
|
||||||
return context.fieldDataCache.getOrPut(this) {
|
return context.fieldDataCache.getOrPut(this) {
|
||||||
val nameCnt = hashMapOf<String, Int>()
|
val nameCnt = hashMapOf<String, Int>()
|
||||||
|
|||||||
+33
-4
@@ -34,9 +34,14 @@ class Merger(
|
|||||||
rename(f.declarations)
|
rename(f.declarations)
|
||||||
rename(f.exports)
|
rename(f.exports)
|
||||||
|
|
||||||
f.imports.entries.forEach { (declaration, importExpression) ->
|
f.imports.entries.forEach { (declaration, importStatement) ->
|
||||||
val importName = nameMap[declaration] ?: error("Missing name for declaration '${declaration}'")
|
val importName = nameMap[declaration]
|
||||||
importStatements.putIfAbsent(declaration, JsVars(JsVars.JsVar(importName, rename(importExpression))))
|
|
||||||
|
if (importName == null && !isEsModules) {
|
||||||
|
error("Missing name for declaration '${declaration}'")
|
||||||
|
}
|
||||||
|
|
||||||
|
importStatements.putIfAbsent(declaration, rename(importStatement).importStatementWithName(importName))
|
||||||
}
|
}
|
||||||
|
|
||||||
val classModels = (mutableMapOf<JsName, JsIrIcClassModel>() + f.classes)
|
val classModels = (mutableMapOf<JsName, JsIrIcClassModel>() + f.classes)
|
||||||
@@ -60,7 +65,6 @@ class Merger(
|
|||||||
|
|
||||||
for ((tag, crossModuleJsImport) in crossModuleReferences.jsImports) {
|
for ((tag, crossModuleJsImport) in crossModuleReferences.jsImports) {
|
||||||
val importName = nameMap[tag] ?: error("Missing name for declaration '$tag'")
|
val importName = nameMap[tag] ?: error("Missing name for declaration '$tag'")
|
||||||
|
|
||||||
importStatements.putIfAbsent(tag, crossModuleJsImport.renameImportedSymbolInternalName(importName))
|
importStatements.putIfAbsent(tag, crossModuleJsImport.renameImportedSymbolInternalName(importName))
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -330,4 +334,29 @@ class Merger(
|
|||||||
this += statements
|
this += statements
|
||||||
endRegion()
|
endRegion()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun JsStatement.importStatementWithName(name: JsName?): JsStatement {
|
||||||
|
if (name == null) return this
|
||||||
|
|
||||||
|
return when (this) {
|
||||||
|
is JsVars -> JsVars(JsVars.JsVar(name, vars.single().initExpression))
|
||||||
|
is JsImport -> JsImport(
|
||||||
|
module,
|
||||||
|
when (target) {
|
||||||
|
is JsImport.Target.All -> JsImport.Target.All(alias = name.makeRef())
|
||||||
|
is JsImport.Target.Default -> JsImport.Target.Default(name = name.makeRef())
|
||||||
|
is JsImport.Target.Elements -> JsImport.Target.Elements(
|
||||||
|
mutableListOf(
|
||||||
|
JsImport.Element(
|
||||||
|
elements.single().name,
|
||||||
|
name.makeRef()
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
is JsCompositeBlock -> JsCompositeBlock(statements.dropLast(1) + statements.last().importStatementWithName(name))
|
||||||
|
else -> error("Unexpected import statement ${this::class.qualifiedName}")
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+9
-17
@@ -53,7 +53,7 @@ object ModuleWrapperTranslation {
|
|||||||
ModuleKind.COMMON_JS -> wrapCommonJs(function, importedModules, program)
|
ModuleKind.COMMON_JS -> wrapCommonJs(function, importedModules, program)
|
||||||
ModuleKind.UMD -> wrapUmd(moduleId, function, importedModules, program)
|
ModuleKind.UMD -> wrapUmd(moduleId, function, importedModules, program)
|
||||||
ModuleKind.PLAIN -> wrapPlain(moduleId, function, importedModules, program)
|
ModuleKind.PLAIN -> wrapPlain(moduleId, function, importedModules, program)
|
||||||
ModuleKind.ES -> wrapEsModule(function, importedModules)
|
ModuleKind.ES -> wrapEsModule(function)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -128,27 +128,19 @@ object ModuleWrapperTranslation {
|
|||||||
return listOf(invocation.makeStmt())
|
return listOf(invocation.makeStmt())
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun wrapEsModule(function: JsFunction, importedModules: List<JsImportedModule>): List<JsStatement> {
|
private fun wrapEsModule(function: JsFunction): List<JsStatement> {
|
||||||
val (alreadyPresentedImportStatements, restStatements) = function.body.statements.partitionIsInstance<JsStatement, JsImport>()
|
val (alreadyPresentedImportStatements, restStatements) = function.body.statements
|
||||||
|
.flatMap { if (it is JsCompositeBlock) it.statements else listOf(it) }
|
||||||
|
.partitionIsInstance<JsStatement, JsImport>()
|
||||||
|
val (multipleElementsImport, defaultImports) = alreadyPresentedImportStatements.partition { it.target is JsImport.Target.Elements }
|
||||||
|
|
||||||
val importStatements = importedModules.zip(function.parameters.drop(1)).map {
|
val mergedImports = multipleElementsImport
|
||||||
JsImport(
|
|
||||||
it.first.getRequireName(true),
|
|
||||||
if (it.first.plainReference == null) {
|
|
||||||
JsImport.Target.All(alias = it.second.name.makeRef())
|
|
||||||
} else {
|
|
||||||
JsImport.Target.Default(name = it.second.name.makeRef())
|
|
||||||
}
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
val alreadyPresentedImportStatementsWithoutDuplicates = alreadyPresentedImportStatements
|
|
||||||
.groupBy { it.module }
|
.groupBy { it.module }
|
||||||
.map { (module, import) ->
|
.map { (module, import) ->
|
||||||
JsImport(module, *import.flatMap { it.elements }.toTypedArray())
|
JsImport(module, *import.flatMap { it.elements }.distinctBy { it.name.ident }.toTypedArray())
|
||||||
}
|
}
|
||||||
|
|
||||||
return importStatements + alreadyPresentedImportStatementsWithoutDuplicates + restStatements.dropLast(1)
|
return mergedImports + defaultImports + restStatements.dropLast(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
+4
@@ -63,6 +63,10 @@ fun <T : JsNode> IrWhen.toJsNode(
|
|||||||
fun jsElementAccess(name: String, receiver: JsExpression?): JsExpression =
|
fun jsElementAccess(name: String, receiver: JsExpression?): JsExpression =
|
||||||
jsElementAccess(JsName(name, false), receiver)
|
jsElementAccess(JsName(name, false), receiver)
|
||||||
|
|
||||||
|
fun JsExpression.putIntoVariableWitName(name: JsName): JsVars {
|
||||||
|
return JsVars(JsVars.JsVar(name, this))
|
||||||
|
}
|
||||||
|
|
||||||
fun jsElementAccess(name: JsName, receiver: JsExpression?): JsExpression =
|
fun jsElementAccess(name: JsName, receiver: JsExpression?): JsExpression =
|
||||||
if (receiver == null || name.ident.isValidES5Identifier()) {
|
if (receiver == null || name.ident.isValidES5Identifier()) {
|
||||||
JsNameRef(name, receiver)
|
JsNameRef(name, receiver)
|
||||||
|
|||||||
+2
-6
@@ -120,12 +120,8 @@ private fun JsNode.computeScopes(): Scope {
|
|||||||
when (val target = import.target) {
|
when (val target = import.target) {
|
||||||
is JsImport.Target.All -> target.alias.name?.let { currentScope.declaredNames += it }
|
is JsImport.Target.All -> target.alias.name?.let { currentScope.declaredNames += it }
|
||||||
is JsImport.Target.Default -> target.name.name?.let { currentScope.declaredNames += it }
|
is JsImport.Target.Default -> target.name.name?.let { currentScope.declaredNames += it }
|
||||||
is JsImport.Target.Elements -> target.elements.forEach { element ->
|
is JsImport.Target.Elements -> target.elements.forEach {
|
||||||
if (element.alias != null) {
|
currentScope.declaredNames += it.alias?.name ?: it.name
|
||||||
element.alias?.name?.let { currentScope.declaredNames += it }
|
|
||||||
} else {
|
|
||||||
currentScope.declaredNames += element.name
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
super.visitImport(import)
|
super.visitImport(import)
|
||||||
|
|||||||
+1
-1
@@ -86,7 +86,7 @@ private class JsIrAstDeserializer(private val source: ByteArray) {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
readRepeated { imports[stringTable[readInt()]] = readExpression() }
|
readRepeated { imports[stringTable[readInt()]] = readStatement() }
|
||||||
|
|
||||||
readRepeated { declarations.statements += readStatement() }
|
readRepeated { declarations.statements += readStatement() }
|
||||||
readRepeated { initializers.statements += readStatement() }
|
readRepeated { initializers.statements += readStatement() }
|
||||||
|
|||||||
+2
-2
@@ -118,9 +118,9 @@ private class JsIrAstSerializer {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
writeCollection(fragment.imports.entries) { (signatureId, expression) ->
|
writeCollection(fragment.imports.entries) { (signatureId, statement) ->
|
||||||
writeInt(internalizeString(signatureId))
|
writeInt(internalizeString(signatureId))
|
||||||
writeExpression(expression)
|
writeStatement(statement)
|
||||||
}
|
}
|
||||||
|
|
||||||
writeCompositeBlock(fragment.declarations)
|
writeCompositeBlock(fragment.declarations)
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ class JsImport(
|
|||||||
|
|
||||||
class Element(
|
class Element(
|
||||||
val name: JsName,
|
val name: JsName,
|
||||||
val alias: JsNameRef?
|
val alias: JsNameRef? = null
|
||||||
)
|
)
|
||||||
|
|
||||||
override fun accept(visitor: JsVisitor) {
|
override fun accept(visitor: JsVisitor) {
|
||||||
|
|||||||
Reference in New Issue
Block a user