diff --git a/compiler/cli/cli-js/src/org/jetbrains/kotlin/cli/js/K2JsIrCompiler.kt b/compiler/cli/cli-js/src/org/jetbrains/kotlin/cli/js/K2JsIrCompiler.kt index 017291e9faa..2f44527dc4d 100644 --- a/compiler/cli/cli-js/src/org/jetbrains/kotlin/cli/js/K2JsIrCompiler.kt +++ b/compiler/cli/cli-js/src/org/jetbrains/kotlin/cli/js/K2JsIrCompiler.kt @@ -77,6 +77,7 @@ import org.jetbrains.kotlin.ir.backend.js.lower.serialization.ir.JsManglerIr import org.jetbrains.kotlin.ir.backend.js.transformers.irToJs.IrModuleToJsTransformer import org.jetbrains.kotlin.ir.backend.js.transformers.irToJs.JsCodeGenerator import org.jetbrains.kotlin.ir.backend.js.transformers.irToJs.TranslationMode +import org.jetbrains.kotlin.ir.backend.js.transformers.irToJs.CompilationOutputsBuilt import org.jetbrains.kotlin.ir.declarations.impl.IrFactoryImpl import org.jetbrains.kotlin.ir.declarations.impl.IrFactoryImplForJsIC import org.jetbrains.kotlin.ir.symbols.IrSymbol @@ -155,7 +156,7 @@ class K2JsIrCompiler : CLICompiler() { return transformer.makeJsCodeGenerator(ir.allModules, mode) } - fun compileAndTransformIrNew(): CompilationOutputs { + fun compileAndTransformIrNew(): CompilationOutputsBuilt { return makeJsCodeGenerator().generateJsCode(relativeRequirePath = true, outJsProgram = false) } } @@ -317,7 +318,7 @@ class K2JsIrCompiler : CLICompiler() { ) val (outputs, rebuiltModules) = jsExecutableProducer.buildExecutable(arguments.irPerModule, outJsProgram = false) - outputs.write(outputDir, outputName, arguments.generateDts, moduleName, moduleKind) + outputs.writeAll(outputDir, outputName, arguments.generateDts, moduleName, moduleKind) messageCollector.report(INFO, "Executable production duration (IC): ${System.currentTimeMillis() - beforeIc2Js}ms") for ((event, duration) in jsExecutableProducer.getStopwatchLaps()) { @@ -393,7 +394,7 @@ class K2JsIrCompiler : CLICompiler() { messageCollector.report(INFO, "Executable production duration: ${System.currentTimeMillis() - start}ms") - outputs.write(outputDir, outputName, arguments.generateDts, moduleName, moduleKind) + outputs.writeAll(outputDir, outputName, arguments.generateDts, moduleName, moduleKind) } catch (e: CompilationException) { messageCollector.report( ERROR, @@ -704,28 +705,6 @@ class K2JsIrCompiler : CLICompiler() { return icCaches } - private fun CompilationOutputs.write(outputDir: File, outputName: String, genDTS: Boolean, moduleName: String, moduleKind: ModuleKind) { - val outputFile = outputDir.resolve("$outputName.js") - outputFile.parentFile.mkdirs() - outputFile.write(this) - dependencies.forEach { (name, content) -> - outputDir.resolve("$name.js").let { - it.parentFile.mkdirs() - it.write(content) - } - } - - if (genDTS) { - val dtsFile = outputDir.resolve("$outputName.d.ts") - dtsFile.writeText(getFullTsDefinition(moduleName, moduleKind)) - } - } - - private fun File.write(outputs: CompilationOutputs) { - writeText(outputs.jsCode) - outputs.writeSourceMapIfPresent(this) - } - override fun setupPlatformSpecificArgumentsAndServices( configuration: CompilerConfiguration, arguments: K2JSCompilerArguments, diff --git a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/compiler.kt b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/compiler.kt index 8f7a9372f16..224a94c3056 100644 --- a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/compiler.kt +++ b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/compiler.kt @@ -11,46 +11,24 @@ import org.jetbrains.kotlin.backend.common.serialization.linkerissues.checkNoUnb import org.jetbrains.kotlin.config.CompilerConfiguration import org.jetbrains.kotlin.ir.IrBuiltIns import org.jetbrains.kotlin.ir.backend.js.codegen.JsGenerationGranularity -import org.jetbrains.kotlin.ir.backend.js.export.TypeScriptFragment -import org.jetbrains.kotlin.ir.backend.js.export.toTypeScript import org.jetbrains.kotlin.ir.backend.js.lower.collectNativeImplementations import org.jetbrains.kotlin.ir.backend.js.lower.generateJsTests import org.jetbrains.kotlin.ir.backend.js.lower.moveBodilessDeclarationsToSeparatePlace import org.jetbrains.kotlin.ir.backend.js.lower.serialization.ir.JsIrLinker +import org.jetbrains.kotlin.ir.backend.js.transformers.irToJs.CompilationOutputs import org.jetbrains.kotlin.ir.backend.js.transformers.irToJs.TranslationMode import org.jetbrains.kotlin.ir.declarations.IrFactory import org.jetbrains.kotlin.ir.declarations.IrModuleFragment import org.jetbrains.kotlin.ir.util.ExternalDependenciesGenerator import org.jetbrains.kotlin.ir.util.SymbolTable -import org.jetbrains.kotlin.js.backend.ast.JsProgram import org.jetbrains.kotlin.js.config.JSConfigurationKeys import org.jetbrains.kotlin.js.config.RuntimeDiagnostic import org.jetbrains.kotlin.name.FqName -import org.jetbrains.kotlin.serialization.js.ModuleKind -import org.jetbrains.kotlin.utils.addToStdlib.ifNotEmpty -import java.io.File class CompilerResult( val outputs: Map, ) -class CompilationOutputs( - val jsCode: String, - val tsDefinitions: TypeScriptFragment? = null, - val jsProgram: JsProgram? = null, - val sourceMap: String? = null, - val dependencies: Iterable> = emptyList() -) { - fun addDependencies(depends: Iterable>): CompilationOutputs { - return CompilationOutputs(jsCode, tsDefinitions, jsProgram, sourceMap, depends) - } - - fun getFullTsDefinition(name: String, moduleKind: ModuleKind): String { - val allTsDefinitions = dependencies.mapNotNull { it.second.tsDefinitions } + listOfNotNull(tsDefinitions) - return allTsDefinitions.toTypeScript(name, moduleKind) - } -} - class LoweredIr( val context: JsIrBackendContext, val mainModule: IrModuleFragment, @@ -163,11 +141,3 @@ fun compileIr( return LoweredIr(context, moduleFragment, allModules, moduleToName) } - -fun CompilationOutputs.writeSourceMapIfPresent(outputJsFile: File) { - sourceMap?.let { - val mapFile = outputJsFile.resolveSibling("${outputJsFile.name}.map") - outputJsFile.appendText("\n//# sourceMappingURL=${mapFile.name}\n") - mapFile.writeText(it) - } -} diff --git a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/ic/JsExecutableProducer.kt b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/ic/JsExecutableProducer.kt index f68c9362022..96423f14b8e 100644 --- a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/ic/JsExecutableProducer.kt +++ b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/ic/JsExecutableProducer.kt @@ -5,7 +5,6 @@ package org.jetbrains.kotlin.ir.backend.js.ic -import org.jetbrains.kotlin.ir.backend.js.CompilationOutputs import org.jetbrains.kotlin.ir.backend.js.SourceMapsInfo import org.jetbrains.kotlin.ir.backend.js.transformers.irToJs.* import org.jetbrains.kotlin.serialization.js.ModuleKind @@ -96,11 +95,10 @@ class JsExecutableProducer( val mainModule = cachedMainModule.compileModule(mainModuleName, true) val cachedOtherModules = cachedProgram.dropLast(1) - val dependencies = cachedOtherModules.map { + mainModule.dependencies = cachedOtherModules.map { it.jsIrHeader.externalModuleName to it.compileModule(it.jsIrHeader.externalModuleName, false) } stopwatch.stop() - val compilationOut = mainModule.addDependencies(dependencies) - return BuildResult(compilationOut, rebuildModules) + return BuildResult(mainModule, rebuildModules) } } diff --git a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/ic/JsMultiModuleCache.kt b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/ic/JsMultiModuleCache.kt index 506c9a369b4..daa31c8d3d0 100644 --- a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/ic/JsMultiModuleCache.kt +++ b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/ic/JsMultiModuleCache.kt @@ -5,10 +5,7 @@ package org.jetbrains.kotlin.ir.backend.js.ic -import org.jetbrains.kotlin.ir.backend.js.CompilationOutputs -import org.jetbrains.kotlin.ir.backend.js.export.TypeScriptFragment -import org.jetbrains.kotlin.ir.backend.js.transformers.irToJs.CrossModuleReferences -import org.jetbrains.kotlin.ir.backend.js.transformers.irToJs.JsIrModuleHeader +import org.jetbrains.kotlin.ir.backend.js.transformers.irToJs.* import java.io.File class JsMultiModuleCache(private val moduleArtifacts: List) { @@ -99,17 +96,19 @@ class JsMultiModuleCache(private val moduleArtifacts: List) { } fun fetchCompiledJsCode(artifact: ModuleArtifact) = artifact.artifactsDir?.let { cacheDir -> - val jsCode = File(cacheDir, CACHED_MODULE_JS).ifExists { readText() } - val sourceMap = File(cacheDir, CACHED_MODULE_JS_MAP).ifExists { readText() } - val tsDefinitions = File(cacheDir, CACHED_MODULE_D_TS).ifExists { TypeScriptFragment(readText()) } - jsCode?.let { CompilationOutputs(it, tsDefinitions, null, sourceMap) } + val jsCodeFilePath = File(cacheDir, CACHED_MODULE_JS).ifExists { absolutePath } + val sourceMapFilePath = File(cacheDir, CACHED_MODULE_JS_MAP).ifExists { absolutePath } + val tsDefinitionsFilePath = File(cacheDir, CACHED_MODULE_D_TS).ifExists { absolutePath } + jsCodeFilePath?.let { CompilationOutputsCached(it, sourceMapFilePath, tsDefinitionsFilePath) } } - fun commitCompiledJsCode(artifact: ModuleArtifact, compilationOutputs: CompilationOutputs) = artifact.artifactsDir?.let { cacheDir -> - File(cacheDir, CACHED_MODULE_JS).writeIfNotNull(compilationOutputs.jsCode) - File(cacheDir, CACHED_MODULE_JS_MAP).writeIfNotNull(compilationOutputs.sourceMap) - File(cacheDir, CACHED_MODULE_D_TS).writeIfNotNull(compilationOutputs.tsDefinitions?.raw) - } + fun commitCompiledJsCode(artifact: ModuleArtifact, compilationOutputs: CompilationOutputsBuilt) = + artifact.artifactsDir?.let { cacheDir -> + val jsCodeFile = File(cacheDir, CACHED_MODULE_JS) + val jsMapFile = File(cacheDir, CACHED_MODULE_JS_MAP) + compilationOutputs.writeJsCode(jsCodeFile, jsMapFile) + File(cacheDir, CACHED_MODULE_D_TS).writeIfNotNull(compilationOutputs.tsDefinitions?.raw) + } fun loadProgramHeadersFromCache(): List { return moduleArtifacts.map { artifact -> diff --git a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/transformers/irToJs/CompilationOutputs.kt b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/transformers/irToJs/CompilationOutputs.kt new file mode 100644 index 00000000000..ea1baadebff --- /dev/null +++ b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/transformers/irToJs/CompilationOutputs.kt @@ -0,0 +1,95 @@ +/* + * Copyright 2010-2022 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package org.jetbrains.kotlin.ir.backend.js.transformers.irToJs + +import org.jetbrains.kotlin.ir.backend.js.export.TypeScriptFragment +import org.jetbrains.kotlin.ir.backend.js.export.toTypeScript +import org.jetbrains.kotlin.js.backend.ast.JsProgram +import org.jetbrains.kotlin.serialization.js.ModuleKind +import java.io.File + +abstract class CompilationOutputs { + var dependencies: Collection> = emptyList() + + abstract val tsDefinitions: TypeScriptFragment? + + abstract val jsProgram: JsProgram? + + abstract fun writeJsCode(outputJsFile: File, outputJsMapFile: File) + + fun writeAll(outputDir: File, outputName: String, genDTS: Boolean, moduleName: String, moduleKind: ModuleKind): List { + val writtenJsFiles = ArrayList(dependencies.size + 1) + + val outputJsFile = outputDir.resolve("$outputName.js") + + outputJsFile.parentFile.mkdirs() + writeJsCode(outputJsFile, outputJsFile.mapForJsFile) + + dependencies.forEach { (name, content) -> + outputDir.resolve("$name.js").let { depJsFile -> + depJsFile.parentFile.mkdirs() + content.writeJsCode(depJsFile, depJsFile.mapForJsFile) + writtenJsFiles += depJsFile.absolutePath + } + } + + writtenJsFiles += outputJsFile.absolutePath + + if (genDTS) { + outputJsFile.dtsForJsFile.writeText(getFullTsDefinition(moduleName, moduleKind)) + } + + return writtenJsFiles + } + + fun getFullTsDefinition(moduleName: String, moduleKind: ModuleKind): String { + val allTsDefinitions = dependencies.mapNotNull { it.second.tsDefinitions } + listOfNotNull(tsDefinitions) + return allTsDefinitions.toTypeScript(moduleName, moduleKind) + } + + private val File.mapForJsFile + get() = resolveSibling("$name.map") + + private val File.dtsForJsFile + get() = resolveSibling("$nameWithoutExtension.d.ts") +} + +class CompilationOutputsBuilt( + private val rawJsCode: String, + private val sourceMap: String?, + override val tsDefinitions: TypeScriptFragment?, + override val jsProgram: JsProgram?, +) : CompilationOutputs() { + override fun writeJsCode(outputJsFile: File, outputJsMapFile: File) { + var jsCodeWithSourceMap = rawJsCode + + sourceMap?.let { + outputJsMapFile.writeText(it) + jsCodeWithSourceMap = "$jsCodeWithSourceMap\n//# sourceMappingURL=${outputJsMapFile.name}\n" + } + outputJsFile.writeText(jsCodeWithSourceMap) + } +} + +class CompilationOutputsCached( + private val jsCodeFilePath: String, + private val sourceMapFilePath: String?, + private val tsDefinitionsFilePath: String? +) : CompilationOutputs() { + override val tsDefinitions: TypeScriptFragment? + get() = tsDefinitionsFilePath?.let { TypeScriptFragment(File(it).readText()) } + + override val jsProgram: JsProgram? + get() = null + + override fun writeJsCode(outputJsFile: File, outputJsMapFile: File) { + File(jsCodeFilePath).copyTo(outputJsFile, true) + + sourceMapFilePath?.let { + File(it).copyTo(outputJsMapFile, true) + } + } +} diff --git a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/transformers/irToJs/IrModuleToJsTransformer.kt b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/transformers/irToJs/IrModuleToJsTransformer.kt index 0a01ee7ee67..e17bf81ea15 100644 --- a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/transformers/irToJs/IrModuleToJsTransformer.kt +++ b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/transformers/irToJs/IrModuleToJsTransformer.kt @@ -81,7 +81,7 @@ class JsCodeGenerator( private val moduleKind: ModuleKind, private val sourceMapsInfo: SourceMapsInfo? ) { - fun generateJsCode(relativeRequirePath: Boolean, outJsProgram: Boolean): CompilationOutputs { + fun generateJsCode(relativeRequirePath: Boolean, outJsProgram: Boolean): CompilationOutputsBuilt { return generateWrappedModuleBody( multiModule, mainModuleName, @@ -380,7 +380,7 @@ private fun generateWrappedModuleBody( sourceMapsInfo: SourceMapsInfo?, relativeRequirePath: Boolean, outJsProgram: Boolean -): CompilationOutputs { +): CompilationOutputsBuilt { if (multiModule) { // mutable container allows explicitly remove elements from itself, // so we are able to help GC to free heavy JsIrModule objects @@ -398,7 +398,7 @@ private fun generateWrappedModuleBody( ) } - val dependencies = buildList(moduleToRef.size) { + mainModule.dependencies = buildList(moduleToRef.size) { while (moduleToRef.isNotEmpty()) { moduleToRef.removeFirst().let { (module, moduleRef) -> val moduleName = module.externalModuleName @@ -416,7 +416,7 @@ private fun generateWrappedModuleBody( } } - return mainModule.addDependencies(dependencies) + return mainModule } else { return generateSingleWrappedModuleBody( mainModuleName, @@ -437,7 +437,7 @@ fun generateSingleWrappedModuleBody( generateCallToMain: Boolean, crossModuleReferences: CrossModuleReferences = CrossModuleReferences.Empty(moduleKind), outJsProgram: Boolean = true -): CompilationOutputs { +): CompilationOutputsBuilt { val program = Merger( moduleName, moduleKind, @@ -476,10 +476,10 @@ fun generateSingleWrappedModuleBody( program.accept(JsToStringGenerationVisitor(jsCode, sourceMapBuilderConsumer)) - return CompilationOutputs( + return CompilationOutputsBuilt( jsCode.toString(), + sourceMapBuilder?.build(), fragments.mapNotNull { it.dts }.ifNotEmpty { joinTypeScriptFragments() }, - program.takeIf { outJsProgram }, - sourceMapBuilder?.build() + program.takeIf { outJsProgram } ) } diff --git a/js/js.tests/test/org/jetbrains/kotlin/incremental/AbstractInvalidationTest.kt b/js/js.tests/test/org/jetbrains/kotlin/incremental/AbstractInvalidationTest.kt index 6f8a037a1d4..e81a10c821e 100644 --- a/js/js.tests/test/org/jetbrains/kotlin/incremental/AbstractInvalidationTest.kt +++ b/js/js.tests/test/org/jetbrains/kotlin/incremental/AbstractInvalidationTest.kt @@ -24,6 +24,7 @@ import org.jetbrains.kotlin.ir.backend.js.* import org.jetbrains.kotlin.ir.backend.js.ic.* import org.jetbrains.kotlin.ir.backend.js.SourceMapsInfo import org.jetbrains.kotlin.ir.backend.js.codegen.JsGenerationGranularity +import org.jetbrains.kotlin.ir.backend.js.transformers.irToJs.CompilationOutputs import org.jetbrains.kotlin.ir.backend.js.transformers.irToJs.safeModuleName import org.jetbrains.kotlin.ir.declarations.impl.IrFactoryImpl import org.jetbrains.kotlin.ir.declarations.impl.IrFactoryImplForJsIC @@ -225,16 +226,6 @@ abstract class AbstractInvalidationTest : KotlinTestWithEnvironment() { writeText(ClassicJsBackendFacade.wrapWithModuleEmulationMarkers(jsCode, JS_MODULE_KIND, moduleName)) } - private fun writeJsFile(name: String, text: String): String { - val moduleFileName = "./$name.js" - val file = File(jsDir, moduleFileName) - if (file.exists()) { - file.delete() - } - file.writeAsJsModule(text, moduleFileName) - return file.canonicalPath - } - private fun prepareExternalJsFiles(): MutableList { jsDir.invalidateDir() return testDir.filesInDir.mapNotNullTo(mutableListOf(MODULE_EMULATION_FILE)) { file -> @@ -249,12 +240,15 @@ abstract class AbstractInvalidationTest : KotlinTestWithEnvironment() { private fun verifyJsCode(stepId: Int, mainModuleName: String, jsOutput: CompilationOutputs) { val files = prepareExternalJsFiles() - jsOutput.dependencies.mapTo(files) { writeJsFile(it.first, it.second.jsCode) } - files += writeJsFile(mainModuleName, jsOutput.jsCode) + val compiledJsFiles = jsOutput.writeAll(jsDir, mainModuleName, true, mainModuleName, JS_MODULE_KIND) + for (jsCodeFile in compiledJsFiles) { + val jsFile = File(jsCodeFile) + jsFile.writeAsJsModule(jsFile.readText(), "./${jsFile.name}") + } try { V8IrJsTestChecker.checkWithTestFunctionArgs( - files = files, + files = files + compiledJsFiles, testModuleName = "./$mainModuleName.js", testPackageName = null, testFunctionName = BOX_FUNCTION_NAME, @@ -269,11 +263,16 @@ abstract class AbstractInvalidationTest : KotlinTestWithEnvironment() { } } - private fun verifyDTS(stepId: Int, testInfo: List, jsOutput: CompilationOutputs) { + private fun verifyDTS(stepId: Int, testInfo: List) { for (info in testInfo) { val expectedDTS = info.expectedDTS ?: continue - val output = jsOutput.dependencies.find { it.first == info.moduleName }?.second ?: jsOutput - val gotDTS = output.getFullTsDefinition(info.moduleName, JS_MODULE_KIND) + + val dtsFile = jsDir.resolve("${File(info.modulePath).nameWithoutExtension}.d.ts") + JUnit4Assertions.assertTrue(dtsFile.exists()) { + "Cannot find d.ts (${dtsFile.absolutePath}) file for module ${info.moduleName} at step $stepId" + } + + val gotDTS = dtsFile.readText() JUnit4Assertions.assertEquals(expectedDTS, gotDTS) { "Mismatched d.ts for module ${info.moduleName} at step $stepId" } @@ -320,7 +319,7 @@ abstract class AbstractInvalidationTest : KotlinTestWithEnvironment() { val (jsOutput, rebuiltModules) = jsExecutableProducer.buildExecutable(multiModule = true, outJsProgram = true) verifyJsExecutableProducerBuildModules(projStep.id, rebuiltModules, projStep.dirtyJS) verifyJsCode(projStep.id, mainModuleName, jsOutput) - verifyDTS(projStep.id, testInfo, jsOutput) + verifyDTS(projStep.id, testInfo) } } } diff --git a/js/js.tests/test/org/jetbrains/kotlin/js/test/converters/JsIrBackendFacade.kt b/js/js.tests/test/org/jetbrains/kotlin/js/test/converters/JsIrBackendFacade.kt index 6866833684f..3ae910c0eb9 100644 --- a/js/js.tests/test/org/jetbrains/kotlin/js/test/converters/JsIrBackendFacade.kt +++ b/js/js.tests/test/org/jetbrains/kotlin/js/test/converters/JsIrBackendFacade.kt @@ -17,6 +17,7 @@ import org.jetbrains.kotlin.ir.backend.js.ic.JsExecutableProducer import org.jetbrains.kotlin.ir.backend.js.lower.serialization.ir.JsManglerDesc import org.jetbrains.kotlin.ir.backend.js.transformers.irToJs.IrModuleToJsTransformer import org.jetbrains.kotlin.ir.backend.js.SourceMapsInfo +import org.jetbrains.kotlin.ir.backend.js.transformers.irToJs.CompilationOutputs import org.jetbrains.kotlin.ir.backend.js.transformers.irToJs.TranslationMode import org.jetbrains.kotlin.ir.declarations.IrModuleFragment import org.jetbrains.kotlin.ir.declarations.impl.IrFactoryImplForJsIC @@ -36,6 +37,7 @@ import org.jetbrains.kotlin.test.frontend.classic.moduleDescriptorProvider import org.jetbrains.kotlin.test.model.* import org.jetbrains.kotlin.test.services.* import org.jetbrains.kotlin.test.services.configuration.JsEnvironmentConfigurator +import org.jetbrains.kotlin.utils.addToStdlib.ifTrue import org.jetbrains.kotlin.utils.fileUtils.withReplacedExtensionOrNull import java.io.File @@ -256,17 +258,28 @@ class JsIrBackendFacade( return this } + fun File.fixJsFile(newJsTarget: File, moduleId: String, moduleKind: ModuleKind) { + val newJsCode = ClassicJsBackendFacade.wrapWithModuleEmulationMarkers(readText(), moduleKind, moduleId) + + val oldJsMap = File("$absolutePath.map") + val jsCodeMap = (moduleKind == ModuleKind.PLAIN && oldJsMap.exists()).ifTrue { oldJsMap.readText() } + + this.delete() + oldJsMap.delete() + + newJsTarget.write(newJsCode) + jsCodeMap?.let { File("${newJsTarget.absolutePath}.map").write(it) } + } + private fun CompilationOutputs.writeTo(outputFile: File, moduleId: String, moduleKind: ModuleKind) { - val wrappedCode = ClassicJsBackendFacade.wrapWithModuleEmulationMarkers(jsCode, moduleId = moduleId, moduleKind = moduleKind) - outputFile.write(wrappedCode) + val allJsFiles = writeAll(outputFile.parentFile, outputFile.nameWithoutExtension, false, moduleId, moduleKind) - if (moduleKind == ModuleKind.PLAIN) { - writeSourceMapIfPresent(outputFile) - } + val mainModuleFile = File(allJsFiles.last()) + mainModuleFile.fixJsFile(outputFile, moduleId, moduleKind) - dependencies.forEach { (moduleId, outputs) -> - val moduleWrappedCode = ClassicJsBackendFacade.wrapWithModuleEmulationMarkers(outputs.jsCode, moduleKind, moduleId) - outputFile.augmentWithModuleName(moduleId).write(moduleWrappedCode) + dependencies.map { it.first }.zip(allJsFiles.dropLast(1)).forEach { (depModuleId, builtJsFilePath) -> + val newFile = outputFile.augmentWithModuleName(depModuleId) + File(builtJsFilePath).fixJsFile(newFile, depModuleId, moduleKind) } } diff --git a/js/js.tests/test/org/jetbrains/kotlin/js/test/handlers/JsLineNumberHandler.kt b/js/js.tests/test/org/jetbrains/kotlin/js/test/handlers/JsLineNumberHandler.kt index e29d07ef782..79ddf90b235 100644 --- a/js/js.tests/test/org/jetbrains/kotlin/js/test/handlers/JsLineNumberHandler.kt +++ b/js/js.tests/test/org/jetbrains/kotlin/js/test/handlers/JsLineNumberHandler.kt @@ -5,7 +5,7 @@ package org.jetbrains.kotlin.js.test.handlers -import org.jetbrains.kotlin.ir.backend.js.CompilationOutputs +import org.jetbrains.kotlin.ir.backend.js.transformers.irToJs.CompilationOutputs import org.jetbrains.kotlin.ir.backend.js.transformers.irToJs.TranslationMode import org.jetbrains.kotlin.ir.backend.js.transformers.irToJs.safeModuleName import org.jetbrains.kotlin.js.backend.ast.JsProgram diff --git a/js/js.tests/test/org/jetbrains/kotlin/js/test/ir/AbstractJsKLibABITestCase.kt b/js/js.tests/test/org/jetbrains/kotlin/js/test/ir/AbstractJsKLibABITestCase.kt index 674a618a916..53a10405560 100644 --- a/js/js.tests/test/org/jetbrains/kotlin/js/test/ir/AbstractJsKLibABITestCase.kt +++ b/js/js.tests/test/org/jetbrains/kotlin/js/test/ir/AbstractJsKLibABITestCase.kt @@ -23,6 +23,7 @@ import org.jetbrains.kotlin.ir.backend.js.* import org.jetbrains.kotlin.ir.backend.js.codegen.JsGenerationGranularity import org.jetbrains.kotlin.ir.backend.js.ic.CacheUpdater import org.jetbrains.kotlin.ir.backend.js.ic.JsExecutableProducer +import org.jetbrains.kotlin.ir.backend.js.transformers.irToJs.CompilationOutputs import org.jetbrains.kotlin.ir.backend.js.transformers.irToJs.IrModuleToJsTransformer import org.jetbrains.kotlin.ir.backend.js.transformers.irToJs.TranslationMode import org.jetbrains.kotlin.ir.declarations.impl.IrFactoryImpl @@ -168,19 +169,10 @@ abstract class AbstractJsKLibABITestCase : KtUsefulTestCase() { buildBinaryNoIC(configuration, mainModuleKlibFile, allDependencies) val binariesDir = File(buildDir, BIN_DIR_NAME).also { it.mkdirs() } - val binaries = ArrayList(allDependencies.regularDependencies.size) - - for ((name, code) in compilationOutputs.dependencies) { - val depBinary = binariesDir.binJsFile(name) - depBinary.parentFile?.let { if (!it.exists()) it.mkdirs() } - depBinary.writeText(code.jsCode) - binaries.add(depBinary) + val binaries = compilationOutputs.writeAll(binariesDir, MAIN_MODULE_NAME, false, MAIN_MODULE_NAME, ModuleKind.PLAIN).map { + File(it) } - val mainBinary = binariesDir.binJsFile(MAIN_MODULE_NAME) - mainBinary.writeText(compilationOutputs.jsCode) - binaries.add(mainBinary) - executeAndCheckBinaries(MAIN_MODULE_NAME, binaries) }