Introduce and use JSConfigurationKeys similar to JVMConfigurationKeys

Use type-safe keys in CompilerConfiguration instead of multiple parameters,
duplicated in the base class (JsConfig), derived class (LibrarySourcesConfig)
and its builder (LibrarySourcesConfig.Builder)
This commit is contained in:
Alexander Udalov
2016-05-23 19:51:52 +03:00
parent b65980f3b7
commit cad4b6973c
10 changed files with 119 additions and 191 deletions
@@ -48,6 +48,7 @@ import org.jetbrains.kotlin.config.Services;
import org.jetbrains.kotlin.js.analyze.TopDownAnalyzerFacadeForJS;
import org.jetbrains.kotlin.js.analyzer.JsAnalysisResult;
import org.jetbrains.kotlin.js.config.EcmaVersion;
import org.jetbrains.kotlin.js.config.JSConfigurationKeys;
import org.jetbrains.kotlin.js.config.JsConfig;
import org.jetbrains.kotlin.js.config.LibrarySourcesConfig;
import org.jetbrains.kotlin.js.facade.K2JSTranslator;
@@ -119,7 +120,7 @@ public class K2JSCompiler extends CLICompiler<K2JSCompilerArguments> {
File outputFile = new File(arguments.outputFile);
JsConfig config = getConfig(project, configuration, arguments);
JsConfig config = new LibrarySourcesConfig(project, configuration);
if (config.checkLibFilesAndReportErrors(new Function1<String, Unit>() {
@Override
public Unit invoke(String message) {
@@ -240,21 +241,24 @@ public class K2JSCompiler extends CLICompiler<K2JSCompilerArguments> {
@Override
protected void setupPlatformSpecificArgumentsAndServices(
@NotNull CompilerConfiguration configuration, @NotNull K2JSCompilerArguments arguments, @NotNull Services services
) {
// No platform-specific arguments yet
}
@NotNull
private static JsConfig getConfig(
@NotNull Project project,
@NotNull CompilerConfiguration configuration,
@NotNull K2JSCompilerArguments arguments
) {
if (arguments.target != null) {
assert arguments.target == "v5" : "Unsupported ECMA version: " + arguments.target;
}
EcmaVersion ecmaVersion = EcmaVersion.defaultVersion();
configuration.put(JSConfigurationKeys.TARGET, EcmaVersion.defaultVersion());
String moduleId = FileUtil.getNameWithoutExtension(new File(arguments.outputFile));
configuration.put(JSConfigurationKeys.MODULE_ID, moduleId);
if (arguments.sourceMap) {
configuration.put(JSConfigurationKeys.SOURCE_MAP, true);
}
if (arguments.metaInfo) {
configuration.put(JSConfigurationKeys.META_INFO, true);
}
if (arguments.kjsm) {
configuration.put(JSConfigurationKeys.KJSM, true);
}
List<String> libraryFiles = new SmartList<String>();
if (!arguments.noStdlib) {
@@ -265,15 +269,10 @@ public class K2JSCompiler extends CLICompiler<K2JSCompilerArguments> {
ContainerUtil.addAllNotNull(libraryFiles, arguments.libraryFiles);
}
return new LibrarySourcesConfig.Builder(project, configuration, moduleId, libraryFiles)
.ecmaVersion(ecmaVersion)
.sourceMap(arguments.sourceMap)
.metaInfo(arguments.metaInfo)
.kjsm(arguments.kjsm)
.build();
configuration.put(JSConfigurationKeys.LIBRARY_FILES, libraryFiles);
}
public static MainCallParameters createMainCallParameters(String main) {
private static MainCallParameters createMainCallParameters(String main) {
if (K2JsArgumentConstants.NO_CALL.equals(main)) {
return MainCallParameters.noCall();
}
@@ -18,9 +18,11 @@ package org.jetbrains.kotlin.checkers;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.kotlin.cli.jvm.compiler.EnvironmentConfigFiles;
import org.jetbrains.kotlin.config.CompilerConfiguration;
import org.jetbrains.kotlin.context.ModuleContext;
import org.jetbrains.kotlin.descriptors.impl.ModuleDescriptorImpl;
import org.jetbrains.kotlin.js.analyze.TopDownAnalyzerFacadeForJS;
import org.jetbrains.kotlin.js.config.JSConfigurationKeys;
import org.jetbrains.kotlin.js.config.JsConfig;
import org.jetbrains.kotlin.js.config.LibrarySourcesConfig;
import org.jetbrains.kotlin.js.resolve.JsPlatform;
@@ -40,9 +42,10 @@ public abstract class AbstractDiagnosticsTestWithJsStdLib extends AbstractDiagno
@Override
protected void setUp() throws Exception {
super.setUp();
config = new LibrarySourcesConfig.Builder(
getProject(), getEnvironment().getConfiguration(), "module", LibrarySourcesConfig.JS_STDLIB
).build();
CompilerConfiguration configuration = getEnvironment().getConfiguration().copy();
configuration.put(JSConfigurationKeys.MODULE_ID, "module");
configuration.put(JSConfigurationKeys.LIBRARY_FILES, LibrarySourcesConfig.JS_STDLIB);
config = new LibrarySourcesConfig(getProject(), configuration);
}
@Override
@@ -26,6 +26,7 @@ import org.jetbrains.kotlin.config.CompilerConfiguration
import org.jetbrains.kotlin.config.addKotlinSourceRoots
import org.jetbrains.kotlin.descriptors.impl.ModuleDescriptorImpl
import org.jetbrains.kotlin.js.analyze.TopDownAnalyzerFacadeForJS
import org.jetbrains.kotlin.js.config.JSConfigurationKeys
import org.jetbrains.kotlin.js.config.LibrarySourcesConfig
import org.jetbrains.kotlin.js.resolve.JsPlatform
import org.jetbrains.kotlin.jvm.compiler.LoadDescriptorUtil.TEST_PACKAGE_FQNAME
@@ -50,6 +51,8 @@ class KotlinJavascriptSerializerTest : TestCaseWithTmpdir() {
val configuration = CompilerConfiguration()
configuration.put(CLIConfigurationKeys.MESSAGE_COLLECTOR_KEY, MessageCollector.NONE)
configuration.put(JSConfigurationKeys.MODULE_ID, MODULE_NAME)
configuration.put(JSConfigurationKeys.LIBRARY_FILES, LibrarySourcesConfig.JS_STDLIB)
configuration.addKotlinSourceRoots(srcDirs.map { it.path })
@@ -68,9 +71,7 @@ class KotlinJavascriptSerializerTest : TestCaseWithTmpdir() {
try {
val environment = KotlinCoreEnvironment.createForTests(rootDisposable, configuration, EnvironmentConfigFiles.JS_CONFIG_FILES)
val files = environment.getSourceFiles()
val config = LibrarySourcesConfig.Builder(
environment.project, environment.configuration, MODULE_NAME, LibrarySourcesConfig.JS_STDLIB
).build()
val config = LibrarySourcesConfig(environment.project, environment.configuration)
val analysisResult = TopDownAnalyzerFacadeForJS.analyzeFiles(files, config)
FileUtil.writeToFile(metaFile, KotlinJavascriptSerializationUtil.metadataAsString(MODULE_NAME, analysisResult.moduleDescriptor))
}
@@ -25,6 +25,7 @@ import org.jetbrains.kotlin.config.CommonConfigurationKeys;
import org.jetbrains.kotlin.config.CompilerConfiguration;
import org.jetbrains.kotlin.idea.test.PluginTestCaseBase;
import org.jetbrains.kotlin.js.analyze.TopDownAnalyzerFacadeForJS;
import org.jetbrains.kotlin.js.config.JSConfigurationKeys;
import org.jetbrains.kotlin.js.config.JsConfig;
import org.jetbrains.kotlin.js.config.LibrarySourcesConfig;
import org.jetbrains.kotlin.js.resolve.diagnostics.ErrorsJs;
@@ -62,9 +63,10 @@ public abstract class AbstractDiagnosticMessageJsTest extends AbstractDiagnostic
@NotNull
private JsConfig getConfig() {
CompilerConfiguration configuration = getEnvironment().getConfiguration().copy();
configuration.put(JSConfigurationKeys.MODULE_ID, "testModule");
configuration.put(JSConfigurationKeys.LIBRARY_FILES, LibrarySourcesConfig.JS_STDLIB);
configuration.put(CommonConfigurationKeys.DISABLE_INLINE, true);
return new LibrarySourcesConfig.Builder(getProject(), configuration, "testModule", LibrarySourcesConfig.JS_STDLIB)
.isUnitTestConfig(true)
.build();
configuration.put(JSConfigurationKeys.UNIT_TEST_CONFIG, true);
return new LibrarySourcesConfig(getProject(), configuration);
}
}
@@ -0,0 +1,42 @@
/*
* 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.config;
import org.jetbrains.kotlin.config.CompilerConfigurationKey;
import java.util.List;
public class JSConfigurationKeys {
public static final CompilerConfigurationKey<List<String>> LIBRARY_FILES =
CompilerConfigurationKey.create("library file paths");
public static final CompilerConfigurationKey<Boolean> SOURCE_MAP =
CompilerConfigurationKey.create("generate source map");
public static final CompilerConfigurationKey<Boolean> META_INFO =
CompilerConfigurationKey.create("generate metadata");
public static final CompilerConfigurationKey<Boolean> KJSM =
CompilerConfigurationKey.create("generate .kjsm files");
public static final CompilerConfigurationKey<EcmaVersion> TARGET =
CompilerConfigurationKey.create("ECMA version target");
public static final CompilerConfigurationKey<Boolean> UNIT_TEST_CONFIG =
CompilerConfigurationKey.create("unit test config");
public static final CompilerConfigurationKey<String> MODULE_ID =
CompilerConfigurationKey.create("module id");
}
@@ -23,7 +23,6 @@ import kotlin.Unit;
import kotlin.collections.CollectionsKt;
import kotlin.jvm.functions.Function1;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.kotlin.config.CompilerConfiguration;
import org.jetbrains.kotlin.descriptors.PackageFragmentProvider;
import org.jetbrains.kotlin.descriptors.impl.ModuleDescriptorImpl;
@@ -43,48 +42,18 @@ import java.util.List;
* Base class representing a configuration of translator.
*/
public abstract class JsConfig {
@NotNull
private final Project project;
@NotNull
private final CompilerConfiguration configuration;
@NotNull
private final LockBasedStorageManager storageManager = new LockBasedStorageManager();
@NotNull
private final List<KtFile> sourceFilesFromLibraries = new SmartList<KtFile>();
@NotNull
private final EcmaVersion target;
@NotNull
private final String moduleId;
private final boolean sourcemap;
private final boolean metaInfo;
private final boolean kjsm;
@NotNull
protected final List<KotlinJavascriptMetadata> metadata = new SmartList<KotlinJavascriptMetadata>();
@Nullable
private List<ModuleDescriptorImpl> moduleDescriptors = null;
private boolean initialized = false;
protected JsConfig(
@NotNull Project project,
@NotNull CompilerConfiguration configuration,
@NotNull String moduleId,
@NotNull EcmaVersion ecmaVersion,
boolean sourcemap,
boolean metaInfo,
boolean kjsm
) {
protected JsConfig(@NotNull Project project, @NotNull CompilerConfiguration configuration) {
this.project = project;
this.configuration = configuration;
this.target = ecmaVersion;
this.moduleId = moduleId;
this.sourcemap = sourcemap;
this.metaInfo = metaInfo;
this.kjsm = kjsm;
}
@NotNull
@@ -92,31 +61,14 @@ public abstract class JsConfig {
return configuration;
}
public boolean isSourcemap() {
return sourcemap;
}
public boolean isMetaInfo() {
return metaInfo;
}
public boolean isKjsm() {
return kjsm;
}
@NotNull
public Project getProject() {
return project;
}
@NotNull
public EcmaVersion getTarget() {
return target;
}
@NotNull
public String getModuleId() {
return moduleId;
return configuration.getNotNull(JSConfigurationKeys.MODULE_ID);
}
public abstract boolean checkLibFilesAndReportErrors(@NotNull Function1<String, Unit> report);
@@ -140,16 +92,11 @@ public abstract class JsConfig {
}
@NotNull
public List<KtFile> getSourceFilesFromLibraries() {
private List<KtFile> getSourceFilesFromLibraries() {
init();
return sourceFilesFromLibraries;
}
public boolean isTestConfig() {
return false;
}
private void init() {
if (initialized) return;
@@ -48,9 +48,7 @@ public class LibrarySourcesConfig extends JsConfig {
public static final List<String> JS_STDLIB =
Collections.singletonList(getKotlinPathsForDistDirectory().getJsStdLibJarPath().getAbsolutePath());
@NotNull
public static final Key<String> EXTERNAL_MODULE_NAME = Key.create("externalModule");
@NotNull
public static final String UNKNOWN_EXTERNAL_MODULE_NAME = "<unknown>";
public static final String STDLIB_JS_MODULE_NAME = "stdlib";
@@ -58,40 +56,18 @@ public class LibrarySourcesConfig extends JsConfig {
public static final String BUILTINS_JS_FILE_NAME = BUILTINS_JS_MODULE_NAME + JavaScript.DOT_EXTENSION;
public static final String STDLIB_JS_FILE_NAME = STDLIB_JS_MODULE_NAME + JavaScript.DOT_EXTENSION;
private final boolean isUnitTestConfig;
@NotNull
private final List<String> files;
private LibrarySourcesConfig(
@NotNull Project project,
@NotNull CompilerConfiguration configuration,
@NotNull String moduleId,
@NotNull List<String> files,
@NotNull EcmaVersion ecmaVersion,
boolean sourceMap,
boolean isUnitTestConfig,
boolean metaInfo,
boolean kjsm
) {
super(project, configuration, moduleId, ecmaVersion, sourceMap, metaInfo, kjsm);
this.files = files;
this.isUnitTestConfig = isUnitTestConfig;
}
@Override
public boolean isTestConfig() {
return isUnitTestConfig;
public LibrarySourcesConfig(@NotNull Project project, @NotNull CompilerConfiguration configuration) {
super(project, configuration);
}
@NotNull
public List<String> getLibraries() {
return files;
return getConfiguration().getList(JSConfigurationKeys.LIBRARY_FILES);
}
@Override
protected void init(@NotNull final List<KtFile> sourceFilesInLibraries, @NotNull final List<KotlinJavascriptMetadata> metadata) {
if (files.isEmpty()) return;
if (getLibraries().isEmpty()) return;
final PsiManager psiManager = PsiManager.getInstance(getProject());
@@ -129,14 +105,15 @@ public class LibrarySourcesConfig extends JsConfig {
}
private boolean checkLibFilesAndReportErrors(@NotNull Function1<String, Unit> report, @Nullable Function2<String, VirtualFile, Unit> action) {
if (files.isEmpty()) {
List<String> libraries = getLibraries();
if (libraries.isEmpty()) {
return false;
}
VirtualFileSystem fileSystem = VirtualFileManager.getInstance().getFileSystem(StandardFileSystems.FILE_PROTOCOL);
VirtualFileSystem jarFileSystem = VirtualFileManager.getInstance().getFileSystem(StandardFileSystems.JAR_PROTOCOL);
for (String path : files) {
for (String path : libraries) {
VirtualFile file;
File filePath = new File(path);
@@ -189,62 +166,7 @@ public class LibrarySourcesConfig extends JsConfig {
return false;
}
public static class Builder {
private final Project project;
private final CompilerConfiguration configuration;
private final String moduleId;
private final List<String> files;
private EcmaVersion ecmaVersion = EcmaVersion.defaultVersion();
boolean sourceMap = false;
boolean isUnitTestConfig = false;
boolean metaInfo = false;
boolean kjsm = false;
public Builder(
@NotNull Project project,
@NotNull CompilerConfiguration configuration,
@NotNull String moduleId,
@NotNull List<String> files
) {
this.project = project;
this.configuration = configuration;
this.moduleId = moduleId;
this.files = files;
}
public Builder ecmaVersion(@NotNull EcmaVersion ecmaVersion) {
this.ecmaVersion = ecmaVersion;
return this;
}
public Builder sourceMap(boolean sourceMap) {
this.sourceMap = sourceMap;
return this;
}
public Builder isUnitTestConfig(boolean isUnitTestConfig) {
this.isUnitTestConfig = isUnitTestConfig;
return this;
}
public Builder metaInfo(boolean metaInfo) {
this.metaInfo = metaInfo;
return this;
}
public Builder kjsm(boolean kjsm) {
this.kjsm = kjsm;
return this;
}
public JsConfig build() {
return new LibrarySourcesConfig(
project, configuration, moduleId, files, ecmaVersion, sourceMap, isUnitTestConfig, metaInfo, kjsm
);
}
}
protected static KtFile getJetFileByVirtualFile(VirtualFile file, String moduleName, PsiManager psiManager) {
private static KtFile getJetFileByVirtualFile(VirtualFile file, String moduleName, PsiManager psiManager) {
PsiFile psiFile = psiManager.findFile(file);
assert psiFile != null;
@@ -252,7 +174,7 @@ public class LibrarySourcesConfig extends JsConfig {
return (KtFile) psiFile;
}
protected static void setupPsiFile(PsiFile psiFile, String moduleName) {
private static void setupPsiFile(PsiFile psiFile, String moduleName) {
psiFile.putUserData(EXTERNAL_MODULE_NAME, moduleName);
}
@@ -40,6 +40,7 @@ import org.jetbrains.kotlin.config.CompilerConfiguration;
import org.jetbrains.kotlin.idea.KotlinFileType;
import org.jetbrains.kotlin.js.JavaScript;
import org.jetbrains.kotlin.js.config.EcmaVersion;
import org.jetbrains.kotlin.js.config.JSConfigurationKeys;
import org.jetbrains.kotlin.js.config.JsConfig;
import org.jetbrains.kotlin.js.config.LibrarySourcesConfig;
import org.jetbrains.kotlin.js.facade.K2JSTranslator;
@@ -329,26 +330,33 @@ public abstract class BasicTest extends KotlinTestWithEnvironment {
) {
CompilerConfiguration configuration = getEnvironment().getConfiguration().copy();
for (KtFile file : files) {
String text = file.getText();
if (isDirectiveDefined(text, NO_INLINE_DIRECTIVE)) {
configuration.put(CommonConfigurationKeys.DISABLE_INLINE, true);
break;
}
}
configuration.put(CommonConfigurationKeys.DISABLE_INLINE, hasNoInline(files));
List<String> librariesWithStdlib = new ArrayList<String>(LibrarySourcesConfig.JS_STDLIB);
if (libraries != null) {
librariesWithStdlib.addAll(libraries);
}
configuration.put(JSConfigurationKeys.LIBRARY_FILES, librariesWithStdlib);
return new LibrarySourcesConfig.Builder(project, configuration, moduleId, librariesWithStdlib)
.ecmaVersion(ecmaVersion)
.sourceMap(shouldGenerateSourceMap())
.isUnitTestConfig(shouldBeTranslateAsUnitTestClass())
.metaInfo(shouldGenerateMetaInfo())
.build();
configuration.put(JSConfigurationKeys.MODULE_ID, moduleId);
configuration.put(JSConfigurationKeys.TARGET, ecmaVersion);
configuration.put(JSConfigurationKeys.SOURCE_MAP, shouldGenerateSourceMap());
configuration.put(JSConfigurationKeys.META_INFO, shouldGenerateMetaInfo());
configuration.put(JSConfigurationKeys.UNIT_TEST_CONFIG, shouldBeTranslateAsUnitTestClass());
return new LibrarySourcesConfig(project, configuration);
}
private static boolean hasNoInline(@NotNull List<KtFile> files) {
for (KtFile file : files) {
if (isDirectiveDefined(file.getText(), NO_INLINE_DIRECTIVE)) {
return true;
}
}
return false;
}
@NotNull
@@ -23,6 +23,7 @@ import com.intellij.openapi.util.text.StringUtil
import com.intellij.openapi.vfs.VfsUtilCore
import org.jetbrains.kotlin.backend.common.output.*
import org.jetbrains.kotlin.descriptors.ModuleDescriptor
import org.jetbrains.kotlin.js.config.JSConfigurationKeys
import org.jetbrains.kotlin.js.config.JsConfig
import org.jetbrains.kotlin.js.sourceMap.JsSourceGenerationVisitor
import org.jetbrains.kotlin.js.sourceMap.SourceMap3Builder
@@ -45,14 +46,15 @@ abstract class TranslationResult protected constructor(val diagnostics: Diagnost
diagnostics: Diagnostics,
private val moduleDescriptor: ModuleDescriptor
) : TranslationResult(diagnostics) {
@Suppress("unused") // Used in kotlin-web-demo in WebDemoTranslatorFacade
fun getCode(): String = getCode(TextOutputImpl(), sourceMapBuilder = null)
fun getOutputFiles(outputFile: File, outputPrefixFile: File?, outputPostfixFile: File?): OutputFileCollection {
val output = TextOutputImpl()
val sourceMapBuilder = when {
config.isSourcemap -> SourceMap3Builder(outputFile, output, SourceMapBuilderConsumer())
else -> null
}
val sourceMapBuilder =
if (config.configuration.getBoolean(JSConfigurationKeys.SOURCE_MAP))
SourceMap3Builder(outputFile, output, SourceMapBuilderConsumer())
else null
val code = getCode(output, sourceMapBuilder)
val prefix = outputPrefixFile?.readText() ?: ""
@@ -69,7 +71,7 @@ abstract class TranslationResult protected constructor(val diagnostics: Diagnost
val jsFile = SimpleOutputFile(sourceFiles, outputFile.name, prefix + code + postfix)
val outputFiles = arrayListOf<OutputFile>(jsFile)
if (config.isMetaInfo) {
if (config.configuration.getBoolean(JSConfigurationKeys.META_INFO)) {
val metaFileName = KotlinJavascriptMetadataUtils.replaceSuffix(outputFile.name)
val metaFileContent = KotlinJavascriptSerializationUtil.metadataAsString(config.moduleId, moduleDescriptor)
val sourceFilesForMetaFile = ArrayList(sourceFiles)
@@ -77,7 +79,7 @@ abstract class TranslationResult protected constructor(val diagnostics: Diagnost
outputFiles.add(jsMetaFile)
}
if (config.isKjsm) {
if (config.configuration.getBoolean(JSConfigurationKeys.KJSM)) {
KotlinJavascriptSerializationUtil.toContentMap(moduleDescriptor).forEach {
// TODO Add correct source files
outputFiles.add(SimpleOutputBinaryFile(emptyList(), config.moduleId + VfsUtilCore.VFS_SEPARATOR_CHAR + it.key, it.value))
@@ -22,6 +22,7 @@ import org.jetbrains.annotations.Nullable;
import org.jetbrains.kotlin.descriptors.FunctionDescriptor;
import org.jetbrains.kotlin.descriptors.ModuleDescriptor;
import org.jetbrains.kotlin.idea.MainFunctionDetector;
import org.jetbrains.kotlin.js.config.JSConfigurationKeys;
import org.jetbrains.kotlin.js.config.JsConfig;
import org.jetbrains.kotlin.js.facade.MainCallParameters;
import org.jetbrains.kotlin.js.facade.exceptions.TranslationException;
@@ -227,7 +228,8 @@ public final class Translation {
private static void mayBeGenerateTests(
@NotNull Collection<KtFile> files, @NotNull JsConfig config, @NotNull JsBlock rootBlock, @NotNull TranslationContext context
) {
JSTester tester = config.isTestConfig() ? new JSRhinoUnitTester() : new QUnitTester();
JSTester tester =
config.getConfiguration().getBoolean(JSConfigurationKeys.UNIT_TEST_CONFIG) ? new JSRhinoUnitTester() : new QUnitTester();
tester.initialize(context, rootBlock);
JSTestGenerator.generateTestCalls(context, files, tester);
tester.deinitialize();