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.Unit;
023    import kotlin.collections.CollectionsKt;
024    import kotlin.jvm.functions.Function1;
025    import org.jetbrains.annotations.NotNull;
026    import org.jetbrains.annotations.Nullable;
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.resolve.TargetPlatformKt;
035    import org.jetbrains.kotlin.serialization.js.JsModuleDescriptor;
036    import org.jetbrains.kotlin.serialization.js.KotlinJavascriptSerializationUtil;
037    import org.jetbrains.kotlin.serialization.js.ModuleKind;
038    import org.jetbrains.kotlin.storage.LockBasedStorageManager;
039    import org.jetbrains.kotlin.utils.KotlinJavascriptMetadata;
040    import org.jetbrains.kotlin.utils.KotlinJavascriptMetadataUtils;
041    
042    import java.util.ArrayList;
043    import java.util.Collection;
044    import java.util.Collections;
045    import java.util.List;
046    
047    /**
048     * Base class representing a configuration of translator.
049     */
050    public abstract class JsConfig {
051        private final boolean inlineEnabled;
052        @NotNull
053        private final Project project;
054        @NotNull
055        private final LockBasedStorageManager storageManager = new LockBasedStorageManager();
056        @NotNull
057        private final List<KtFile> sourceFilesFromLibraries = new SmartList<KtFile>();
058        @NotNull
059        private final EcmaVersion target;
060    
061        @NotNull
062        private final String moduleId;
063    
064        @NotNull
065        private final ModuleKind moduleKind;
066    
067        private final boolean sourcemap;
068        private final boolean metaInfo;
069        private final boolean kjsm;
070    
071        @NotNull
072        protected final List<KotlinJavascriptMetadata> metadata = new SmartList<KotlinJavascriptMetadata>();
073    
074        @Nullable
075        private List<JsModuleDescriptor<ModuleDescriptorImpl>> moduleDescriptors = null;
076    
077        private boolean initialized = false;
078    
079        protected JsConfig(
080                @NotNull Project project,
081                @NotNull String moduleId,
082                @NotNull ModuleKind moduleKind,
083                @NotNull EcmaVersion ecmaVersion,
084                boolean sourcemap,
085                boolean inlineEnabled,
086                boolean metaInfo,
087                boolean kjsm
088        ) {
089            this.project = project;
090            this.target = ecmaVersion;
091            this.moduleId = moduleId;
092            this.moduleKind = moduleKind;
093            this.sourcemap = sourcemap;
094            this.inlineEnabled = inlineEnabled;
095            this.metaInfo = metaInfo;
096            this.kjsm = kjsm;
097        }
098    
099        public boolean isSourcemap() {
100            return sourcemap;
101        }
102    
103        public boolean isMetaInfo() {
104            return metaInfo;
105        }
106    
107        public boolean isKjsm() {
108            return kjsm;
109        }
110    
111        public boolean isInlineEnabled() {
112            return inlineEnabled;
113        }
114    
115        @NotNull
116        public Project getProject() {
117            return project;
118        }
119    
120        @NotNull
121        public String getModuleId() {
122            return moduleId;
123        }
124    
125        @NotNull
126        public ModuleKind getModuleKind() {
127            return moduleKind;
128        }
129    
130        public abstract boolean checkLibFilesAndReportErrors(@NotNull Function1<String, Unit> report);
131    
132        protected abstract void init(@NotNull List<KtFile> sourceFilesInLibraries, @NotNull List<KotlinJavascriptMetadata> metadata);
133    
134        @NotNull
135        public List<JsModuleDescriptor<ModuleDescriptorImpl>> getModuleDescriptors() {
136            init();
137            if (moduleDescriptors != null) return moduleDescriptors;
138    
139            moduleDescriptors = new SmartList<JsModuleDescriptor<ModuleDescriptorImpl>>();
140            List<ModuleDescriptorImpl> kotlinModuleDescriptors = new ArrayList<ModuleDescriptorImpl>();
141            for (KotlinJavascriptMetadata metadataEntry : metadata) {
142                JsModuleDescriptor<ModuleDescriptorImpl> descriptor = createModuleDescriptor(metadataEntry);
143                moduleDescriptors.add(descriptor);
144                kotlinModuleDescriptors.add(descriptor.getData());
145            }
146    
147            for (JsModuleDescriptor<ModuleDescriptorImpl> module : moduleDescriptors) {
148                // TODO: remove downcast
149                setDependencies(module.getData(), kotlinModuleDescriptors);
150            }
151    
152            moduleDescriptors = Collections.unmodifiableList(moduleDescriptors);
153    
154            return moduleDescriptors;
155        }
156    
157        @NotNull
158        public List<KtFile> getSourceFilesFromLibraries() {
159            init();
160            return sourceFilesFromLibraries;
161        }
162    
163    
164        public boolean isTestConfig() {
165            return false;
166        }
167    
168        private void init() {
169            if (initialized) return;
170    
171            init(sourceFilesFromLibraries, metadata);
172            initialized = true;
173        }
174    
175        private JsModuleDescriptor<ModuleDescriptorImpl> createModuleDescriptor(KotlinJavascriptMetadata metadata) {
176            assert metadata.isAbiVersionCompatible() :
177                    "expected abi version " + KotlinJavascriptMetadataUtils.ABI_VERSION +
178                    ", but metadata.abiVersion = " + metadata.getAbiVersion();
179    
180            ModuleDescriptorImpl moduleDescriptor = TargetPlatformKt.createModule(
181                    JsPlatform.INSTANCE, Name.special("<" + metadata.getModuleName() + ">"), storageManager
182            );
183    
184            JsModuleDescriptor<PackageFragmentProvider> rawDescriptor = KotlinJavascriptSerializationUtil.readModule(
185                    metadata.getBody(), storageManager, moduleDescriptor, new CompilerDeserializationConfiguration(
186                            LanguageVersionSettingsImpl.DEFAULT
187                    )
188            );
189    
190            PackageFragmentProvider provider = rawDescriptor.getData();
191            moduleDescriptor.initialize(provider != null ? provider : PackageFragmentProvider.Empty.INSTANCE);
192    
193            return rawDescriptor.copy(moduleDescriptor);
194        }
195    
196        private static void setDependencies(ModuleDescriptorImpl module, List<ModuleDescriptorImpl> modules) {
197            module.setDependencies(CollectionsKt.plus(modules, JsPlatform.INSTANCE.getBuiltIns().getBuiltInsModule()));
198        }
199    
200        @NotNull
201        public static Collection<KtFile> withJsLibAdded(@NotNull Collection<KtFile> files, @NotNull JsConfig config) {
202            Collection<KtFile> allFiles = Lists.newArrayList();
203            allFiles.addAll(files);
204            allFiles.addAll(config.getSourceFilesFromLibraries());
205            return allFiles;
206        }
207    }