diff --git a/js/js.tests/js.tests.iml b/js/js.tests/js.tests.iml
index 5a346486074..be90c8dbeab 100644
--- a/js/js.tests/js.tests.iml
+++ b/js/js.tests/js.tests.iml
@@ -16,5 +16,6 @@
+
\ No newline at end of file
diff --git a/js/js.tests/test/org/jetbrains/kotlin/js/test/BasicTest.java b/js/js.tests/test/org/jetbrains/kotlin/js/test/BasicTest.java
index a3145e3ff3e..a07a65e7204 100644
--- a/js/js.tests/test/org/jetbrains/kotlin/js/test/BasicTest.java
+++ b/js/js.tests/test/org/jetbrains/kotlin/js/test/BasicTest.java
@@ -81,6 +81,7 @@ public abstract class BasicTest extends KotlinTestWithEnvironment {
private static final String OUT = "out/";
private static final String EXPECTED = "expected/";
private static final String COMMON_FILES_DIR = "_commonFiles/";
+ public static final String MODULE_EMULATION_FILE = TEST_DATA_DIR_PATH + "/moduleEmulation.js";
public static final String TEST_MODULE = "JS_TESTS";
public static final String TEST_PACKAGE = "foo";
@@ -346,6 +347,8 @@ public abstract class BasicTest extends KotlinTestWithEnvironment {
configuration.put(JSConfigurationKeys.UNIT_TEST_CONFIG, shouldBeTranslateAsUnitTestClass());
+ setupConfig(configBuilder);
+
return new LibrarySourcesConfig(project, configuration);
}
@@ -359,6 +362,10 @@ public abstract class BasicTest extends KotlinTestWithEnvironment {
return false;
}
+ protected void setupConfig(@NotNull CompilerConfiguration configuration) {
+ // Do nothing by default, expect inheritors to implement this method
+ }
+
@NotNull
protected String getOutputPath() {
return pathToTestDir() + OUT;
diff --git a/js/js.tests/test/org/jetbrains/kotlin/js/test/MultipleModulesTranslationTest.kt b/js/js.tests/test/org/jetbrains/kotlin/js/test/MultipleModulesTranslationTest.kt
index c96dc2d0a48..d44fd6f17c7 100644
--- a/js/js.tests/test/org/jetbrains/kotlin/js/test/MultipleModulesTranslationTest.kt
+++ b/js/js.tests/test/org/jetbrains/kotlin/js/test/MultipleModulesTranslationTest.kt
@@ -16,22 +16,24 @@
package org.jetbrains.kotlin.js.test
-import com.google.dart.compiler.backend.js.ast.JsProgram
+import com.intellij.openapi.util.io.FileUtil
+import com.intellij.openapi.util.text.StringUtil
+import org.jetbrains.kotlin.js.config.Config
import org.jetbrains.kotlin.js.config.EcmaVersion
+import org.jetbrains.kotlin.js.config.LibrarySourcesConfig
import org.jetbrains.kotlin.js.facade.MainCallParameters
import org.jetbrains.kotlin.js.test.rhino.RhinoFunctionResultChecker
-import org.jetbrains.kotlin.js.test.utils.DirectiveTestUtils
-import org.jetbrains.kotlin.js.test.utils.JsTestUtils
import org.jetbrains.kotlin.js.test.utils.JsTestUtils.getAllFilesInDir
+import org.jetbrains.kotlin.psi.KtFile
+import org.jetbrains.kotlin.serialization.js.ModuleKind
import org.jetbrains.kotlin.utils.KotlinJavascriptMetadataUtils
import java.io.File
-import java.util.ArrayList
import java.util.LinkedHashMap
abstract class MultipleModulesTranslationTest(main: String) : BasicTest(main) {
-
private val MAIN_MODULE_NAME: String = "main"
private var dependencies: Map>? = null
+ protected var moduleKind = ModuleKind.PLAIN
override fun checkFooBoxIsOkByPath(filePath: String) {
val dirName = getTestName(true)
@@ -68,10 +70,23 @@ abstract class MultipleModulesTranslationTest(main: String) : BasicTest(main) {
private fun getMetaFileOutputPath(moduleDirectoryName: String, version: EcmaVersion) =
KotlinJavascriptMetadataUtils.replaceSuffix(getOutputFilePath(moduleDirectoryName, version))
+ override fun setupConfig(builder: LibrarySourcesConfig.Builder) {
+ val method = try {
+ javaClass.getMethod(name)
+ }
+ catch (e: NoSuchMethodException) {
+ return
+ }
+
+ method.getAnnotation(WithModuleKind::class.java)?.let { moduleKind = it.value }
+ builder.moduleKind(moduleKind)
+ }
+
override fun shouldGenerateMetaInfo() = true
override fun additionalJsFiles(ecmaVersion: EcmaVersion): List {
- val result = super.additionalJsFiles(ecmaVersion)
+ val result = mutableListOf(MODULE_EMULATION_FILE)
+ result += super.additionalJsFiles(ecmaVersion)
val dirName = getTestName(true)
assert(dependencies != null) { "dependencies should not be null" }
@@ -84,6 +99,20 @@ abstract class MultipleModulesTranslationTest(main: String) : BasicTest(main) {
return result
}
+ override fun translateFiles(jetFiles: MutableList, outputFile: File, mainCallParameters: MainCallParameters,
+ config: Config) {
+ super.translateFiles(jetFiles, outputFile, mainCallParameters, config)
+
+ if (config.moduleKind == ModuleKind.COMMON_JS) {
+ val content = FileUtil.loadFile(outputFile, true)
+ val wrappedContent = "__beginModule__();\n" +
+ "$content\n" +
+ "__endModule__(\"${StringUtil.escapeStringCharacters(config.moduleId)}\");"
+ FileUtil.writeToFile(outputFile, wrappedContent)
+ // TODO: it would be better to wrap output before JS file is actually written
+ }
+ }
+
private fun readModuleDependencies(testDataDir: String): Map> {
val dependenciesTxt = upsearchFile(testDataDir, "dependencies.txt")
assert(dependenciesTxt.isFile) { "moduleDependencies should not be null" }
diff --git a/js/js.tests/test/org/jetbrains/kotlin/js/test/WithModuleKind.kt b/js/js.tests/test/org/jetbrains/kotlin/js/test/WithModuleKind.kt
new file mode 100644
index 00000000000..c4dfb3dbd2d
--- /dev/null
+++ b/js/js.tests/test/org/jetbrains/kotlin/js/test/WithModuleKind.kt
@@ -0,0 +1,23 @@
+/*
+ * Copyright 2010-2016 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.js.test
+
+import org.jetbrains.kotlin.serialization.js.ModuleKind
+
+@Retention(AnnotationRetention.RUNTIME)
+@Target(AnnotationTarget.FUNCTION)
+annotation class WithModuleKind(val value: ModuleKind)
diff --git a/js/js.tests/test/org/jetbrains/kotlin/js/test/rhino/RhinoFunctionResultChecker.java b/js/js.tests/test/org/jetbrains/kotlin/js/test/rhino/RhinoFunctionResultChecker.java
index 55ef5293396..c420e9aa147 100644
--- a/js/js.tests/test/org/jetbrains/kotlin/js/test/rhino/RhinoFunctionResultChecker.java
+++ b/js/js.tests/test/org/jetbrains/kotlin/js/test/rhino/RhinoFunctionResultChecker.java
@@ -55,10 +55,10 @@ public class RhinoFunctionResultChecker implements RhinoResultChecker {
return cx.evaluateString(scope, functionCallString(), "function call", 0, null);
}
- protected String functionCallString() {
+ private String functionCallString() {
StringBuilder sb = new StringBuilder();
if (packageName != null) {
- sb.append("this");
+ sb.append("kotlin.modules");
if (moduleId.contains(".")) {
sb.append("['").append(moduleId).append("']");
} else {
diff --git a/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/MultiModuleWrappersTest.kt b/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/MultiModuleWrappersTest.kt
new file mode 100644
index 00000000000..9f450130746
--- /dev/null
+++ b/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/MultiModuleWrappersTest.kt
@@ -0,0 +1,66 @@
+/*
+ * Copyright 2010-2016 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.
+ */
+
+/*
+ * Copyright 2010-2016 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.js.test.semantics
+
+import org.jetbrains.kotlin.js.test.MultipleModulesTranslationTest
+import org.jetbrains.kotlin.js.test.WithModuleKind
+import org.jetbrains.kotlin.serialization.js.ModuleKind
+
+class MultiModuleWrappersTest() : MultipleModulesTranslationTest("multiModuleWrappers/") {
+ private var overridenTestName = ""
+
+ @WithModuleKind(ModuleKind.AMD) fun testAmd() {
+ runTest("simple")
+ }
+
+ @WithModuleKind(ModuleKind.COMMON_JS) fun testCommonJs() {
+ runTest("simple")
+ }
+
+ @WithModuleKind(ModuleKind.UMD) fun testUmd() {
+ runTest("simple")
+ }
+
+ @WithModuleKind(ModuleKind.UMD) fun testPlain() {
+ runTest("simple")
+ }
+
+ fun runTest(name: String) {
+ overridenTestName = name
+ doTest("${pathToTestDir()}/cases/$name")
+ }
+
+ override fun getTestName(lowercaseFirstLetter: Boolean) = overridenTestName
+
+ override fun getOutputPath() = "${super.getOutputPath()}/${moduleKind.name.toLowerCase()}/"
+}
diff --git a/js/js.translator/testData/moduleEmulation.js b/js/js.translator/testData/moduleEmulation.js
new file mode 100644
index 00000000000..eefbca5ca49
--- /dev/null
+++ b/js/js.translator/testData/moduleEmulation.js
@@ -0,0 +1,30 @@
+(function(global) {
+ var modules = { kotlin: kotlin };
+ var module = { exports: {} };
+
+ function require(moduleId) {
+ return modules[moduleId];
+ }
+
+ function beginModule() {
+ module.exports = {};
+ }
+
+ function endModule(moduleId) {
+ modules[moduleId] = module.exports;
+ }
+
+ function define(moduleId, dependencies, body) {
+ var resolvedDependencies = [];
+ for (var i = 0; i < dependencies.length; ++i) {
+ resolvedDependencies.push(modules[dependencies[i]]);
+ }
+ modules[moduleId] = body.apply(null, resolvedDependencies);
+ }
+
+ global.require = require;
+ global.define = define;
+ global.__beginModule__ = beginModule;
+ global.__endModule__ = endModule;
+ global.module = module;
+})(this);
\ No newline at end of file
diff --git a/js/js.translator/testData/multiModuleWrappers/cases/simple/dependencies.txt b/js/js.translator/testData/multiModuleWrappers/cases/simple/dependencies.txt
new file mode 100644
index 00000000000..6db4872a51a
--- /dev/null
+++ b/js/js.translator/testData/multiModuleWrappers/cases/simple/dependencies.txt
@@ -0,0 +1,2 @@
+module1->
+main->module1
\ No newline at end of file
diff --git a/js/js.translator/testData/multiModuleWrappers/cases/simple/main/main.kt b/js/js.translator/testData/multiModuleWrappers/cases/simple/main/main.kt
new file mode 100644
index 00000000000..7b089fa128c
--- /dev/null
+++ b/js/js.translator/testData/multiModuleWrappers/cases/simple/main/main.kt
@@ -0,0 +1,4 @@
+fun box(): String {
+ assertEquals("bar", bar())
+ return "OK"
+}
\ No newline at end of file
diff --git a/js/js.translator/testData/multiModuleWrappers/cases/simple/module1/module1.kt b/js/js.translator/testData/multiModuleWrappers/cases/simple/module1/module1.kt
new file mode 100644
index 00000000000..7ebd3013b6b
--- /dev/null
+++ b/js/js.translator/testData/multiModuleWrappers/cases/simple/module1/module1.kt
@@ -0,0 +1 @@
+fun bar() = "bar"
\ No newline at end of file