001    /*
002     * Copyright 2010-2015 JetBrains s.r.o.
003     *
004     * Licensed under the Apache License, Version 2.0 (the "License");
005     * you may not use this file except in compliance with the License.
006     * You may obtain a copy of the License at
007     *
008     * http://www.apache.org/licenses/LICENSE-2.0
009     *
010     * Unless required by applicable law or agreed to in writing, software
011     * distributed under the License is distributed on an "AS IS" BASIS,
012     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013     * See the License for the specific language governing permissions and
014     * limitations under the License.
015     */
016    
017    package org.jetbrains.kotlin.js.config;
018    
019    import com.google.common.collect.Lists;
020    import com.intellij.openapi.project.Project;
021    import com.intellij.util.SmartList;
022    import kotlin.collections.CollectionsKt;
023    import org.jetbrains.annotations.NotNull;
024    import org.jetbrains.annotations.Nullable;
025    import org.jetbrains.kotlin.config.CommonConfigurationKeys;
026    import org.jetbrains.kotlin.config.CompilerConfiguration;
027    import org.jetbrains.kotlin.config.LanguageVersionSettingsImpl;
028    import org.jetbrains.kotlin.descriptors.PackageFragmentProvider;
029    import org.jetbrains.kotlin.descriptors.impl.ModuleDescriptorImpl;
030    import org.jetbrains.kotlin.js.resolve.JsPlatform;
031    import org.jetbrains.kotlin.name.Name;
032    import org.jetbrains.kotlin.psi.KtFile;
033    import org.jetbrains.kotlin.resolve.CompilerDeserializationConfiguration;
034    import org.jetbrains.kotlin.serialization.js.JsModuleDescriptor;
035    import org.jetbrains.kotlin.serialization.js.KotlinJavascriptSerializationUtil;
036    import org.jetbrains.kotlin.serialization.js.ModuleKind;
037    import org.jetbrains.kotlin.storage.LockBasedStorageManager;
038    import org.jetbrains.kotlin.utils.JsMetadataVersion;
039    import org.jetbrains.kotlin.utils.KotlinJavascriptMetadata;
040    
041    import java.util.ArrayList;
042    import java.util.Collection;
043    import java.util.Collections;
044    import java.util.List;
045    
046    /**
047     * Base class representing a configuration of translator.
048     */
049    public abstract class JsConfig {
050        private final Project project;
051        private final CompilerConfiguration configuration;
052        private final LockBasedStorageManager storageManager = new LockBasedStorageManager();
053        private final List<KtFile> sourceFilesFromLibraries = new SmartList<KtFile>();
054    
055        @NotNull
056        protected final List<KotlinJavascriptMetadata> metadata = new SmartList<KotlinJavascriptMetadata>();
057    
058        @Nullable
059        private List<JsModuleDescriptor<ModuleDescriptorImpl>> moduleDescriptors = null;
060    
061        private boolean initialized = false;
062    
063        protected JsConfig(@NotNull Project project, @NotNull CompilerConfiguration configuration) {
064            this.project = project;
065            this.configuration = configuration;
066        }
067    
068        @NotNull
069        public CompilerConfiguration getConfiguration() {
070            return configuration;
071        }
072    
073        @NotNull
074        public Project getProject() {
075            return project;
076        }
077    
078        @NotNull
079        public String getModuleId() {
080            return configuration.getNotNull(CommonConfigurationKeys.MODULE_NAME);
081        }
082    
083        @NotNull
084        public ModuleKind getModuleKind() {
085            return configuration.get(JSConfigurationKeys.MODULE_KIND, ModuleKind.PLAIN);
086        }
087    
088        public static abstract class Reporter {
089            public void error(@NotNull String message) { /*Do nothing*/ }
090            public void warning(@NotNull String message) { /*Do nothing*/ }
091        }
092    
093        public abstract boolean checkLibFilesAndReportErrors(@NotNull Reporter report);
094    
095        protected abstract void init(@NotNull List<KtFile> sourceFilesInLibraries, @NotNull List<KotlinJavascriptMetadata> metadata);
096    
097        @NotNull
098        public List<JsModuleDescriptor<ModuleDescriptorImpl>> getModuleDescriptors() {
099            init();
100            if (moduleDescriptors != null) return moduleDescriptors;
101    
102            moduleDescriptors = new SmartList<JsModuleDescriptor<ModuleDescriptorImpl>>();
103            List<ModuleDescriptorImpl> kotlinModuleDescriptors = new ArrayList<ModuleDescriptorImpl>();
104            for (KotlinJavascriptMetadata metadataEntry : metadata) {
105                JsModuleDescriptor<ModuleDescriptorImpl> descriptor = createModuleDescriptor(metadataEntry);
106                moduleDescriptors.add(descriptor);
107                kotlinModuleDescriptors.add(descriptor.getData());
108            }
109    
110            for (JsModuleDescriptor<ModuleDescriptorImpl> module : moduleDescriptors) {
111                // TODO: remove downcast
112                setDependencies(module.getData(), kotlinModuleDescriptors);
113            }
114    
115            moduleDescriptors = Collections.unmodifiableList(moduleDescriptors);
116    
117            return moduleDescriptors;
118        }
119    
120        @NotNull
121        private List<KtFile> getSourceFilesFromLibraries() {
122            init();
123            return sourceFilesFromLibraries;
124        }
125    
126        private void init() {
127            if (initialized) return;
128    
129            init(sourceFilesFromLibraries, metadata);
130            initialized = true;
131        }
132    
133        private JsModuleDescriptor<ModuleDescriptorImpl> createModuleDescriptor(KotlinJavascriptMetadata metadata) {
134            assert metadata.getVersion().isCompatible() :
135                    "Expected JS metadata version " + JsMetadataVersion.INSTANCE + ", but actual metadata version is " + metadata.getVersion();
136    
137            ModuleDescriptorImpl moduleDescriptor = new ModuleDescriptorImpl(
138                    Name.special("<" + metadata.getModuleName() + ">"), storageManager, JsPlatform.INSTANCE.getBuiltIns()
139            );
140    
141            JsModuleDescriptor<PackageFragmentProvider> rawDescriptor = KotlinJavascriptSerializationUtil.readModule(
142                    metadata.getBody(), storageManager, moduleDescriptor, new CompilerDeserializationConfiguration(
143                            configuration.get(CommonConfigurationKeys.LANGUAGE_VERSION_SETTINGS, LanguageVersionSettingsImpl.DEFAULT)
144                    )
145            );
146    
147            PackageFragmentProvider provider = rawDescriptor.getData();
148            moduleDescriptor.initialize(provider != null ? provider : PackageFragmentProvider.Empty.INSTANCE);
149    
150            return rawDescriptor.copy(moduleDescriptor);
151        }
152    
153        private static void setDependencies(ModuleDescriptorImpl module, List<ModuleDescriptorImpl> modules) {
154            module.setDependencies(CollectionsKt.plus(modules, JsPlatform.INSTANCE.getBuiltIns().getBuiltInsModule()));
155        }
156    
157        @NotNull
158        public static Collection<KtFile> withJsLibAdded(@NotNull Collection<KtFile> files, @NotNull JsConfig config) {
159            Collection<KtFile> allFiles = Lists.newArrayList();
160            allFiles.addAll(files);
161            allFiles.addAll(config.getSourceFilesFromLibraries());
162            return allFiles;
163        }
164    }