diff --git a/compiler/backend-common/src/org/jetbrains/kotlin/backend/common/output/output.kt b/compiler/backend-common/src/org/jetbrains/kotlin/backend/common/output/output.kt index 1fc1aeec9a3..9d5380b5a49 100644 --- a/compiler/backend-common/src/org/jetbrains/kotlin/backend/common/output/output.kt +++ b/compiler/backend-common/src/org/jetbrains/kotlin/backend/common/output/output.kt @@ -43,5 +43,16 @@ public class SimpleOutputFile( override fun asByteArray(): ByteArray = content.toByteArray() override fun asText(): String = content + override fun toString() = "$relativePath (compiled from $sourceFiles)" +} + +public class SimpleOutputBinaryFile( + override val sourceFiles: List, + override val relativePath: String, + private val content: ByteArray +) : OutputFile { + override fun asByteArray(): ByteArray = content + override fun asText(): String = String(content) + override fun toString() = "$relativePath (compiled from $sourceFiles)" } \ No newline at end of file diff --git a/compiler/cli/cli-common/src/org/jetbrains/kotlin/cli/common/arguments/K2JSCompilerArguments.java b/compiler/cli/cli-common/src/org/jetbrains/kotlin/cli/common/arguments/K2JSCompilerArguments.java index d89d5e8968d..843d93dd106 100644 --- a/compiler/cli/cli-common/src/org/jetbrains/kotlin/cli/common/arguments/K2JSCompilerArguments.java +++ b/compiler/cli/cli-common/src/org/jetbrains/kotlin/cli/common/arguments/K2JSCompilerArguments.java @@ -41,6 +41,9 @@ public class K2JSCompilerArguments extends CommonCompilerArguments { @Argument(value = "meta-info", description = "Generate metadata") public boolean metaInfo; + @Argument(value = "kjsm", description = "Generate kjsm-files (for creating libraries)") + public boolean kjsm; + @Argument(value = "target", description = "Generate JS files for specific ECMA version (only ECMA 5 is supported)") @ValueDescription("") public String target; diff --git a/compiler/cli/src/org/jetbrains/kotlin/cli/js/K2JSCompiler.java b/compiler/cli/src/org/jetbrains/kotlin/cli/js/K2JSCompiler.java index 0d4b2ee1898..f5d7d3f4390 100644 --- a/compiler/cli/src/org/jetbrains/kotlin/cli/js/K2JSCompiler.java +++ b/compiler/cli/src/org/jetbrains/kotlin/cli/js/K2JSCompiler.java @@ -264,6 +264,7 @@ public class K2JSCompiler extends CLICompiler { .sourceMap(arguments.sourceMap) .inlineEnabled(inlineEnabled) .metaInfo(arguments.metaInfo) + .kjsm(arguments.kjsm) .build(); } diff --git a/compiler/testData/cli/js/createKjsm.args b/compiler/testData/cli/js/createKjsm.args new file mode 100644 index 00000000000..1dccd4c93ab --- /dev/null +++ b/compiler/testData/cli/js/createKjsm.args @@ -0,0 +1,5 @@ +compiler/testData/integration/ant/js/simpleWithoutStdlibAndFolderAsAnotherLib/jslib-example/LibraryExample.kt +-no-stdlib +-kjsm +-output +$TEMP_DIR$/jslib-example.js diff --git a/compiler/testData/cli/js/createKjsm.out b/compiler/testData/cli/js/createKjsm.out new file mode 100644 index 00000000000..d86bac9de59 --- /dev/null +++ b/compiler/testData/cli/js/createKjsm.out @@ -0,0 +1 @@ +OK diff --git a/compiler/testData/cli/js/createMetadata.args b/compiler/testData/cli/js/createMetadata.args index 8ea42e28941..ae8b5661c1e 100644 --- a/compiler/testData/cli/js/createMetadata.args +++ b/compiler/testData/cli/js/createMetadata.args @@ -1,5 +1,6 @@ compiler/testData/integration/ant/js/simpleWithoutStdlibAndFolderAsAnotherLib/jslib-example/LibraryExample.kt -no-stdlib -meta-info +-kjsm -output $TEMP_DIR$/jslib-example.js diff --git a/compiler/testData/cli/js/jsHelp.out b/compiler/testData/cli/js/jsHelp.out index b75d28fd799..1a50c9cd577 100644 --- a/compiler/testData/cli/js/jsHelp.out +++ b/compiler/testData/cli/js/jsHelp.out @@ -5,6 +5,7 @@ where possible options include: -library-files Path to zipped library sources or kotlin files separated by commas -source-map Generate source map -meta-info Generate metadata + -kjsm Generate kjsm-files (for creating libraries) -target Generate JS files for specific ECMA version (only ECMA 5 is supported) -main {call,noCall} Whether a main function should be called; default 'call' (main function will be auto detected) -output-prefix Path to file which will be added to the beginning of output file diff --git a/compiler/tests/org/jetbrains/kotlin/cli/KotlincExecutableTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/cli/KotlincExecutableTestGenerated.java index 09662097b1a..36ad8cd8473 100644 --- a/compiler/tests/org/jetbrains/kotlin/cli/KotlincExecutableTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/cli/KotlincExecutableTestGenerated.java @@ -274,6 +274,12 @@ public class KotlincExecutableTestGenerated extends AbstractKotlincExecutableTes KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/cli/js"), Pattern.compile("^(.+)\\.args$"), false); } + @TestMetadata("createKjsm.args") + public void testCreateKjsm() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/cli/js/createKjsm.args"); + doJsTest(fileName); + } + @TestMetadata("createMetadata.args") public void testCreateMetadata() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/cli/js/createMetadata.args"); diff --git a/compiler/tests/org/jetbrains/kotlin/cli/js/K2JsCliTest.java b/compiler/tests/org/jetbrains/kotlin/cli/js/K2JsCliTest.java index 31354b358d0..769b859903d 100644 --- a/compiler/tests/org/jetbrains/kotlin/cli/js/K2JsCliTest.java +++ b/compiler/tests/org/jetbrains/kotlin/cli/js/K2JsCliTest.java @@ -97,6 +97,15 @@ public class K2JsCliTest extends CliBaseTest { Assert.assertTrue(new File(tmpdir.getTmpDir(), "jslib-example.meta.js").isFile()); Assert.assertTrue(new File(tmpdir.getTmpDir(), "jslib-example.js").isFile()); + Assert.assertTrue(new File(tmpdir.getTmpDir(), "jslib-example/library/sample/classA.kjsm").isFile()); + } + + @Test + public void createKjsm() throws Exception { + executeCompilerCompareOutputJS(); + + Assert.assertTrue(new File(tmpdir.getTmpDir(), "jslib-example.js").isFile()); + Assert.assertTrue(new File(tmpdir.getTmpDir(), "jslib-example/library/sample/classA.kjsm").isFile()); } @Test diff --git a/js/js.frontend/src/org/jetbrains/kotlin/js/config/Config.java b/js/js.frontend/src/org/jetbrains/kotlin/js/config/Config.java index 5a8e3b873a2..50344f5c627 100644 --- a/js/js.frontend/src/org/jetbrains/kotlin/js/config/Config.java +++ b/js/js.frontend/src/org/jetbrains/kotlin/js/config/Config.java @@ -57,6 +57,7 @@ public abstract class Config { private final boolean sourcemap; private final boolean metaInfo; + private final boolean kjsm; @NotNull protected final List metadata = new SmartList(); @@ -72,7 +73,8 @@ public abstract class Config { @NotNull EcmaVersion ecmaVersion, boolean sourcemap, boolean inlineEnabled, - boolean metaInfo + boolean metaInfo, + boolean kjsm ) { this.project = project; this.target = ecmaVersion; @@ -80,6 +82,7 @@ public abstract class Config { this.sourcemap = sourcemap; this.inlineEnabled = inlineEnabled; this.metaInfo = metaInfo; + this.kjsm = kjsm; } public boolean isSourcemap() { @@ -90,6 +93,10 @@ public abstract class Config { return metaInfo; } + public boolean isKjsm() { + return kjsm; + } + public boolean isInlineEnabled() { return inlineEnabled; } diff --git a/js/js.frontend/src/org/jetbrains/kotlin/js/config/LibrarySourcesConfig.java b/js/js.frontend/src/org/jetbrains/kotlin/js/config/LibrarySourcesConfig.java index 59a8f45eb44..67d35a82e45 100644 --- a/js/js.frontend/src/org/jetbrains/kotlin/js/config/LibrarySourcesConfig.java +++ b/js/js.frontend/src/org/jetbrains/kotlin/js/config/LibrarySourcesConfig.java @@ -70,9 +70,10 @@ public class LibrarySourcesConfig extends Config { boolean sourceMap, boolean inlineEnabled, boolean isUnitTestConfig, - boolean metaInfo + boolean metaInfo, + boolean kjsm ) { - super(project, moduleId, ecmaVersion, sourceMap, inlineEnabled, metaInfo); + super(project, moduleId, ecmaVersion, sourceMap, inlineEnabled, metaInfo, kjsm); this.files = files; this.isUnitTestConfig = isUnitTestConfig; } @@ -197,6 +198,7 @@ public class LibrarySourcesConfig extends Config { boolean inlineEnabled = true; boolean isUnitTestConfig = false; boolean metaInfo = false; + boolean kjsm = false; public Builder(@NotNull Project project, @NotNull String moduleId, @NotNull List files) { this.project = project; @@ -229,8 +231,13 @@ public class LibrarySourcesConfig extends Config { return this; } + public Builder kjsm(boolean kjsm) { + this.kjsm = kjsm; + return this; + } + public Config build() { - return new LibrarySourcesConfig(project, moduleId, files, ecmaVersion, sourceMap, inlineEnabled, isUnitTestConfig, metaInfo); + return new LibrarySourcesConfig(project, moduleId, files, ecmaVersion, sourceMap, inlineEnabled, isUnitTestConfig, metaInfo, kjsm); } } 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 7128b3f2bbf..fb094ae7739 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 @@ -168,11 +168,11 @@ public object KotlinJavascriptSerializationUtil { return KotlinJavascriptSerializedResourcePaths.getClassMetadataPath(classDescriptor.classId) } - private fun ModuleDescriptor.toContentMap(): Map { + public fun toContentMap(module: ModuleDescriptor): Map { val contentMap = hashMapOf() - getPackagesFqNames(this).forEach { - serializePackage(this, it) { + getPackagesFqNames(module).forEach { + serializePackage(module, it) { fileName, bytes -> contentMap[fileName] = bytes } } @@ -218,7 +218,7 @@ public object KotlinJavascriptSerializationUtil { } private fun ModuleDescriptor.toBinaryMetadata(): ByteArray = - KotlinJavascriptSerializationUtil.contentMapToByteArray(this.toContentMap()) + KotlinJavascriptSerializationUtil.contentMapToByteArray(toContentMap(this)) } public fun KotlinJavascriptMetadata.forEachFile(operation: (filePath: String, fileContent: ByteArray) -> Unit): Unit = 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 a1856e729e3..153c5e21d00 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 @@ -21,9 +21,7 @@ import com.google.dart.compiler.util.TextOutput import com.google.dart.compiler.util.TextOutputImpl import com.intellij.openapi.util.text.StringUtil import com.intellij.openapi.vfs.VfsUtilCore -import org.jetbrains.kotlin.backend.common.output.OutputFileCollection -import org.jetbrains.kotlin.backend.common.output.SimpleOutputFile -import org.jetbrains.kotlin.backend.common.output.SimpleOutputFileCollection +import org.jetbrains.kotlin.backend.common.output.* import org.jetbrains.kotlin.descriptors.ModuleDescriptor import org.jetbrains.kotlin.js.config.Config import org.jetbrains.kotlin.js.sourceMap.JsSourceGenerationVisitor @@ -70,7 +68,7 @@ public abstract class TranslationResult protected constructor(public val diagnos } val jsFile = SimpleOutputFile(sourceFiles, outputFile.getName(), prefix + code + postfix) - val outputFiles = arrayListOf(jsFile) + val outputFiles = arrayListOf(jsFile) if (config.isMetaInfo()) { val metaFileName = KotlinJavascriptMetadataUtils.replaceSuffix(outputFile.getName()) @@ -80,6 +78,13 @@ public abstract class TranslationResult protected constructor(public val diagnos outputFiles.add(jsMetaFile) } + if (config.isKjsm) { + KotlinJavascriptSerializationUtil.toContentMap(moduleDescriptor).forEach { + // TODO Add correct source files + outputFiles.add(SimpleOutputBinaryFile(emptyList(), config.moduleId + VfsUtilCore.VFS_SEPARATOR_CHAR + it.key, it.value)) + } + } + if (sourceMapBuilder != null) { sourceMapBuilder.skipLinesAtBeginning(StringUtil.getLineBreakCount(prefix)) val sourceMapFile = SimpleOutputFile(sourceFiles, sourceMapBuilder.getOutFile().getName(), sourceMapBuilder.build())