KT-3008 Change the way how modules are referenced in JS
This commit is contained in:
@@ -106,6 +106,8 @@ public final class Namer {
|
||||
private static final JsNameRef JS_OBJECT = new JsNameRef("Object");
|
||||
private static final JsNameRef JS_OBJECT_CREATE_FUNCTION = new JsNameRef("create", JS_OBJECT);
|
||||
|
||||
public static final String LOCAL_MODULE_PREFIX = "$module$";
|
||||
|
||||
public static boolean isUndefined(@NotNull JsExpression expr) {
|
||||
if (expr instanceof JsPrefixOperation) {
|
||||
JsUnaryOperator op = ((JsPrefixOperation) expr).getOperator();
|
||||
@@ -511,4 +513,30 @@ public final class Namer {
|
||||
public static JsNameRef createInlineFunction() {
|
||||
return pureFqn(DEFINE_INLINE_FUNCTION, kotlinObject());
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static String suggestedModuleName(@NotNull String id) {
|
||||
if (id.isEmpty()) {
|
||||
return "_";
|
||||
}
|
||||
|
||||
StringBuilder sb = new StringBuilder(id.length());
|
||||
char c = id.charAt(0);
|
||||
if (Character.isJavaIdentifierStart(c)) {
|
||||
sb.append(c);
|
||||
}
|
||||
else {
|
||||
sb.append('_');
|
||||
if (Character.isJavaIdentifierPart(c)) {
|
||||
sb.append(c);
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 1; i < id.length(); ++i) {
|
||||
c = id.charAt(i);
|
||||
sb.append(Character.isJavaIdentifierPart(c) ? c : '_');
|
||||
}
|
||||
|
||||
return sb.toString();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -41,10 +41,7 @@ import org.jetbrains.kotlin.resolve.BindingTrace;
|
||||
import org.jetbrains.kotlin.resolve.DescriptorUtils;
|
||||
import org.jetbrains.kotlin.resolve.calls.util.FakeCallableDescriptorForObject;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Collections;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.*;
|
||||
|
||||
import static org.jetbrains.kotlin.js.translate.utils.AnnotationsUtils.*;
|
||||
import static org.jetbrains.kotlin.js.translate.utils.JsAstUtils.pureFqn;
|
||||
@@ -556,13 +553,11 @@ public final class StaticContext {
|
||||
|
||||
JsName moduleId = importedModules.get(moduleName);
|
||||
if (moduleId == null) {
|
||||
moduleId = rootScope.declareFreshName(suggestedModuleName(moduleName));
|
||||
moduleId = rootScope.declareFreshName(Namer.LOCAL_MODULE_PREFIX + Namer.suggestedModuleName(moduleName));
|
||||
importedModules.put(moduleName, moduleId);
|
||||
}
|
||||
// TODO: use just generated moduleId to refer to module. This requires to rewrite how JS module is written
|
||||
|
||||
return JsAstUtils.replaceRootReference(
|
||||
result, namer.getModuleReference(program.getStringLiteral(moduleName)));
|
||||
return JsAstUtils.replaceRootReference(result, JsAstUtils.pureFqn(moduleId, null));
|
||||
}
|
||||
};
|
||||
Rule<JsExpression> constructorOrCompanionObjectHasTheSameQualifierAsTheClass = new Rule<JsExpression>() {
|
||||
@@ -656,40 +651,6 @@ public final class StaticContext {
|
||||
}
|
||||
}
|
||||
|
||||
private static String suggestedModuleName(String id) {
|
||||
if (id.isEmpty()) {
|
||||
return "_";
|
||||
}
|
||||
|
||||
StringBuilder sb = new StringBuilder(id.length());
|
||||
char c = id.charAt(0);
|
||||
if (Character.isJavaIdentifierStart(c)) {
|
||||
sb.append(c);
|
||||
}
|
||||
else {
|
||||
sb.append('_');
|
||||
if (Character.isJavaIdentifierPart(c)) {
|
||||
sb.append(c);
|
||||
}
|
||||
}
|
||||
|
||||
sb.append(Character.isJavaIdentifierStart(c) ? c : '_');
|
||||
for (int i = 1; i < id.length(); ++i) {
|
||||
c = id.charAt(i);
|
||||
sb.append(Character.isJavaIdentifierPart(c) ? c : '_');
|
||||
}
|
||||
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static ClassDescriptor getEnclosing(@Nullable DeclarationDescriptor descriptor) {
|
||||
while (descriptor != null && !(descriptor instanceof ClassDescriptor)) {
|
||||
descriptor = descriptor.getContainingDeclaration();
|
||||
}
|
||||
return (ClassDescriptor) descriptor;
|
||||
}
|
||||
|
||||
private static JsExpression applySideEffects(JsExpression expression, DeclarationDescriptor descriptor) {
|
||||
if (expression instanceof HasMetadata) {
|
||||
if (descriptor instanceof FunctionDescriptor ||
|
||||
|
||||
@@ -42,6 +42,7 @@ import org.jetbrains.kotlin.js.translate.test.JSTestGenerator;
|
||||
import org.jetbrains.kotlin.js.translate.test.JSTester;
|
||||
import org.jetbrains.kotlin.js.translate.test.QUnitTester;
|
||||
import org.jetbrains.kotlin.js.translate.utils.JsAstUtils;
|
||||
import org.jetbrains.kotlin.js.translate.utils.JsDescriptorUtils;
|
||||
import org.jetbrains.kotlin.js.translate.utils.mutator.AssignToExpressionMutator;
|
||||
import org.jetbrains.kotlin.psi.KtDeclarationWithBody;
|
||||
import org.jetbrains.kotlin.psi.KtExpression;
|
||||
@@ -51,6 +52,7 @@ import org.jetbrains.kotlin.resolve.BindingTrace;
|
||||
import org.jetbrains.kotlin.resolve.bindingContextUtil.BindingContextUtilsKt;
|
||||
import org.jetbrains.kotlin.utils.ExceptionUtilsKt;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
@@ -196,9 +198,8 @@ public final class Translation {
|
||||
) {
|
||||
StaticContext staticContext = StaticContext.generateStaticContext(bindingTrace, config, moduleDescriptor);
|
||||
JsProgram program = staticContext.getProgram();
|
||||
JsBlock block = program.getGlobalBlock();
|
||||
|
||||
JsFunction rootFunction = JsAstUtils.createPackage(block.getStatements(), program.getScope());
|
||||
JsFunction rootFunction = JsAstUtils.createFunctionWithEmptyBody(program.getScope());
|
||||
JsBlock rootBlock = rootFunction.getBody();
|
||||
List<JsStatement> statements = rootBlock.getStatements();
|
||||
statements.add(program.getStringLiteral("use strict").makeStmt());
|
||||
@@ -206,6 +207,31 @@ public final class Translation {
|
||||
TranslationContext context = TranslationContext.rootContext(staticContext, rootFunction);
|
||||
statements.addAll(PackageDeclarationTranslator.translateFiles(files, context));
|
||||
defineModule(context, statements, config.getModuleId());
|
||||
statements.add(new JsReturn(program.getRootScope().declareName(Namer.getRootPackageName()).makeRef()));
|
||||
|
||||
mayBeGenerateTests(files, config, rootBlock, context);
|
||||
|
||||
JsBlock block = program.getGlobalBlock();
|
||||
|
||||
// Invoke function passing modules as arguments
|
||||
// This should help minifier tool to recognize references to this modules as local variables and make them shorter.
|
||||
List<JsExpression> invocationArgs = new ArrayList<JsExpression>(staticContext.getImportedModules().size() + 1);
|
||||
JsName kotlinName = program.getScope().declareName(Namer.KOTLIN_NAME);
|
||||
rootFunction.getParameters().add(new JsParameter((kotlinName)));
|
||||
invocationArgs.add(kotlinName.makeRef());
|
||||
|
||||
for (String importedModule : staticContext.getImportedModules().keySet()) {
|
||||
rootFunction.getParameters().add(new JsParameter(staticContext.getImportedModules().get(importedModule)));
|
||||
|
||||
JsName globalId = program.getScope().declareName(Namer.suggestedModuleName(importedModule));
|
||||
invocationArgs.add(JsAstUtils.pureFqn(globalId, null));
|
||||
}
|
||||
JsInvocation invocation = new JsInvocation(rootFunction, invocationArgs);
|
||||
|
||||
String thisModuleName = JsDescriptorUtils.getModuleNameFromDescriptorName(moduleDescriptor);
|
||||
JsName thisModuleId = program.getScope().declareName(Namer.suggestedModuleName(thisModuleName));
|
||||
block.getStatements().add(JsAstUtils.newVar(thisModuleId,
|
||||
new JsBinaryOperation(JsBinaryOperator.OR, thisModuleId.makeRef(), invocation)));
|
||||
|
||||
if (mainCallParameters.shouldBeGenerated()) {
|
||||
JsStatement statement = generateCallToMain(context, files, mainCallParameters.arguments());
|
||||
@@ -213,7 +239,7 @@ public final class Translation {
|
||||
statements.add(statement);
|
||||
}
|
||||
}
|
||||
mayBeGenerateTests(files, config, rootBlock, context);
|
||||
|
||||
return context;
|
||||
}
|
||||
|
||||
|
||||
@@ -442,18 +442,6 @@ public final class JsAstUtils {
|
||||
return dataDescriptor;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static JsFunction createPackage(@NotNull List<JsStatement> to, @NotNull JsObjectScope scope) {
|
||||
JsFunction packageBlockFunction = createFunctionWithEmptyBody(scope);
|
||||
|
||||
JsName kotlinObjectAsParameter = packageBlockFunction.getScope().declareNameUnsafe(Namer.KOTLIN_NAME);
|
||||
packageBlockFunction.getParameters().add(new JsParameter(kotlinObjectAsParameter));
|
||||
|
||||
to.add(new JsInvocation(packageBlockFunction, Namer.kotlinObject()).makeStmt());
|
||||
|
||||
return packageBlockFunction;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static JsObjectLiteral wrapValue(@NotNull JsExpression label, @NotNull JsExpression value) {
|
||||
return new JsObjectLiteral(Collections.singletonList(new JsPropertyInitializer(label, value)));
|
||||
|
||||
@@ -197,7 +197,7 @@ public final class JsDescriptorUtils {
|
||||
return element.getContainingFile().getUserData(LibrarySourcesConfig.EXTERNAL_MODULE_NAME);
|
||||
}
|
||||
|
||||
private static String getModuleNameFromDescriptorName(DeclarationDescriptor descriptor) {
|
||||
public static String getModuleNameFromDescriptorName(DeclarationDescriptor descriptor) {
|
||||
ModuleDescriptor moduleDescriptor = DescriptorUtils.getContainingModule(descriptor);
|
||||
String moduleName = moduleDescriptor.getName().asString();
|
||||
return moduleName.substring(1, moduleName.length() - 1);
|
||||
|
||||
@@ -31,7 +31,7 @@ fun expandIsCalls(node: JsNode, context: TranslationContext) {
|
||||
private class TypeCheckRewritingVisitor(private val context: TranslationContext) : JsVisitorWithContextImpl() {
|
||||
|
||||
private val scopes = Stack<JsScope>()
|
||||
private val localVars = Stack<MutableSet<JsName>>()
|
||||
private val localVars = Stack<MutableSet<JsName>>().apply { push(mutableSetOf()) }
|
||||
|
||||
override fun visit(x: JsFunction, ctx: JsContext<*>): Boolean {
|
||||
scopes.push(x.scope)
|
||||
|
||||
+1
@@ -14,6 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
var Kotlin = Kotlin || {};
|
||||
(function (Kotlin) {
|
||||
"use strict";
|
||||
|
||||
|
||||
+1
-1
@@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
var Kotlin = {};
|
||||
var Kotlin = Kotlin || {};
|
||||
|
||||
(function (Kotlin) {
|
||||
'use strict';
|
||||
|
||||
Vendored
+2
@@ -26,6 +26,8 @@
|
||||
// distributed under the License is distributed on an "AS-IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
|
||||
var Kotlin = Kotlin || {};
|
||||
|
||||
(function (Kotlin) {
|
||||
"use strict";
|
||||
|
||||
|
||||
Vendored
+2
@@ -14,6 +14,8 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
var Kotlin = Kotlin || {};
|
||||
|
||||
(function (Kotlin) {
|
||||
"use strict";
|
||||
|
||||
|
||||
+2
@@ -0,0 +1,2 @@
|
||||
module1->
|
||||
main->module1
|
||||
+6
@@ -0,0 +1,6 @@
|
||||
fun box(): String {
|
||||
var module1 = bar()
|
||||
assertEquals("bar", module1)
|
||||
|
||||
return "OK"
|
||||
}
|
||||
+1
@@ -0,0 +1 @@
|
||||
fun bar() = "bar"
|
||||
Reference in New Issue
Block a user