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