JS: add -Xmetadata-only flag for JS common code modules (KT-33142 fixed)
This commit is contained in:
@@ -69,4 +69,7 @@ public class JSConfigurationKeys {
|
||||
|
||||
public static final CompilerConfigurationKey<List<String>> FRIEND_PATHS =
|
||||
CompilerConfigurationKey.create("friend module paths");
|
||||
|
||||
public static final CompilerConfigurationKey<Boolean> METADATA_ONLY =
|
||||
CompilerConfigurationKey.create("generate .meta.js and .kjsm files only");
|
||||
}
|
||||
|
||||
@@ -48,7 +48,7 @@ import org.jetbrains.kotlin.js.backend.ast.JsProgramFragment
|
||||
import org.jetbrains.kotlin.js.backend.ast.JsStatement
|
||||
import org.jetbrains.kotlin.js.coroutine.transformCoroutines
|
||||
import org.jetbrains.kotlin.js.inline.util.collectDefinedNamesInAllScopes
|
||||
import org.jetbrains.kotlin.js.translate.general.AstGenerationResult
|
||||
import org.jetbrains.kotlin.js.translate.general.SourceFileTranslationResult
|
||||
import org.jetbrains.kotlin.metadata.ProtoBuf
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
import org.jetbrains.kotlin.resolve.BindingContext
|
||||
@@ -101,7 +101,47 @@ class K2JSTranslator @JvmOverloads constructor(
|
||||
|
||||
ProgressIndicatorAndCompilationCanceledStatus.checkCanceled()
|
||||
|
||||
return translate(reporter, files, units, mainCallParameters, actualAnalysisResult, packageMetadata)
|
||||
if (config.configuration.getBoolean(JSConfigurationKeys.METADATA_ONLY)) {
|
||||
return translateWithoutCode(files, actualAnalysisResult, packageMetadata)
|
||||
} else {
|
||||
return translate(reporter, files, units, mainCallParameters, actualAnalysisResult, packageMetadata)
|
||||
}
|
||||
}
|
||||
|
||||
private fun translateWithoutCode(
|
||||
files: List<KtFile>,
|
||||
analysisResult: JsAnalysisResult,
|
||||
packageMetadata: MutableMap<FqName, ByteArray>
|
||||
): TranslationResult {
|
||||
val bindingTrace = analysisResult.bindingTrace
|
||||
TopDownAnalyzerFacadeForJS.checkForErrors(files, bindingTrace.bindingContext)
|
||||
val moduleDescriptor = analysisResult.moduleDescriptor
|
||||
val diagnostics = bindingTrace.bindingContext.diagnostics
|
||||
val pathResolver = SourceFilePathResolver.create(config)
|
||||
val bindingContext = bindingTrace.bindingContext
|
||||
|
||||
checkCanceled()
|
||||
|
||||
updateMetadataMap(bindingTrace.bindingContext, moduleDescriptor, packageMetadata)
|
||||
trySaveIncrementalData(files, pathResolver, bindingTrace, moduleDescriptor) { sourceFile ->
|
||||
TranslationData(sourceFile.declarations.map {
|
||||
BindingUtils.getDescriptorForElement(bindingContext, it)
|
||||
})
|
||||
}
|
||||
|
||||
return if (hasError(diagnostics)) {
|
||||
TranslationResult.Fail(diagnostics)
|
||||
} else {
|
||||
TranslationResult.SuccessNoCode(
|
||||
config,
|
||||
files,
|
||||
diagnostics,
|
||||
emptyList(),
|
||||
moduleDescriptor,
|
||||
bindingTrace.bindingContext,
|
||||
packageMetadata
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Throws(TranslationException::class)
|
||||
@@ -142,7 +182,9 @@ class K2JSTranslator @JvmOverloads constructor(
|
||||
checkCanceled()
|
||||
|
||||
updateMetadataMap(bindingTrace.bindingContext, moduleDescriptor, packageMetadata)
|
||||
trySaveIncrementalData(translationResult, pathResolver, bindingTrace, moduleDescriptor)
|
||||
trySaveIncrementalData(translationResult.translatedSourceFiles.keys, pathResolver, bindingTrace, moduleDescriptor) { sourceFile ->
|
||||
toTranslationData(translationResult.translatedSourceFiles[sourceFile]!!)
|
||||
}
|
||||
checkCanceled()
|
||||
|
||||
// Global phases
|
||||
@@ -177,7 +219,8 @@ class K2JSTranslator @JvmOverloads constructor(
|
||||
bindingContext,
|
||||
moduleDescriptor,
|
||||
config.configuration.languageVersionSettings,
|
||||
config.configuration.get(CommonConfigurationKeys.METADATA_VERSION) as? JsMetadataVersion ?: JsMetadataVersion.INSTANCE)
|
||||
config.configuration.get(CommonConfigurationKeys.METADATA_VERSION) as? JsMetadataVersion ?: JsMetadataVersion.INSTANCE
|
||||
)
|
||||
|
||||
for ((packageName, metadata) in additionalMetadata) {
|
||||
incrementalResults?.processPackageMetadata(packageName.asString(), metadata)
|
||||
@@ -207,11 +250,33 @@ class K2JSTranslator @JvmOverloads constructor(
|
||||
)
|
||||
}
|
||||
|
||||
private class TranslationData(
|
||||
val memberScope: Collection<DeclarationDescriptor>,
|
||||
val binaryAst: ByteArray? = null,
|
||||
val inlineData: ByteArray? = null
|
||||
)
|
||||
|
||||
private fun JsAstSerializer.toTranslationData(fileTranslationResult: SourceFileTranslationResult): TranslationData {
|
||||
val fragment = fileTranslationResult.fragment
|
||||
val output = ByteArrayOutputStream()
|
||||
serialize(fragment, output)
|
||||
val binaryAst = output.toByteArray()
|
||||
|
||||
val inlineData = serializeInlineData(fileTranslationResult.inlineFunctionTags)
|
||||
|
||||
return TranslationData(
|
||||
memberScope = fileTranslationResult.memberScope,
|
||||
binaryAst = binaryAst,
|
||||
inlineData = inlineData
|
||||
)
|
||||
}
|
||||
|
||||
private fun trySaveIncrementalData(
|
||||
translationResult: AstGenerationResult,
|
||||
sourceFiles: Iterable<KtFile>,
|
||||
pathResolver: SourceFilePathResolver,
|
||||
bindingTrace: BindingTrace,
|
||||
moduleDescriptor: ModuleDescriptor
|
||||
moduleDescriptor: ModuleDescriptor,
|
||||
translationData: JsAstSerializer.(KtFile) -> TranslationData
|
||||
) {
|
||||
// TODO Maybe switch validation on for recompile
|
||||
if (incrementalResults == null && !shouldValidateJsAst) return
|
||||
@@ -224,19 +289,19 @@ class K2JSTranslator @JvmOverloads constructor(
|
||||
}
|
||||
}
|
||||
|
||||
for ((sourceUnit, fileTranslationResult) in translationResult.translatedSourceFiles) {
|
||||
val file = sourceUnit.file
|
||||
val fragment = fileTranslationResult.fragment
|
||||
val output = ByteArrayOutputStream()
|
||||
serializer.serialize(fragment, output)
|
||||
val binaryAst = output.toByteArray()
|
||||
for (file in sourceFiles) {
|
||||
val fileTranslationData = serializer.translationData(file)
|
||||
|
||||
val packagePart = serializeScope(bindingTrace.bindingContext, moduleDescriptor, file.packageFqName, fileTranslationResult.memberScope)
|
||||
|
||||
val inlineData = serializeInlineData(fileTranslationResult.inlineFunctionTags)
|
||||
val packagePart =
|
||||
serializeScope(bindingTrace.bindingContext, moduleDescriptor, file.packageFqName, fileTranslationData.memberScope)
|
||||
|
||||
val ioFile = VfsUtilCore.virtualToIoFile(file.virtualFile)
|
||||
incrementalResults?.processPackagePart(ioFile, packagePart.toByteArray(), binaryAst, inlineData)
|
||||
incrementalResults?.processPackagePart(
|
||||
ioFile,
|
||||
packagePart.toByteArray(),
|
||||
fileTranslationData.binaryAst ?: ByteArray(0),
|
||||
fileTranslationData.inlineData ?: ByteArray(0)
|
||||
)
|
||||
}
|
||||
|
||||
val settings = config.configuration.languageVersionSettings
|
||||
|
||||
@@ -48,62 +48,28 @@ import java.util.*
|
||||
abstract class TranslationResult protected constructor(val diagnostics: Diagnostics) {
|
||||
class Fail(diagnostics: Diagnostics) : TranslationResult(diagnostics)
|
||||
|
||||
class Success(
|
||||
private val config: JsConfig,
|
||||
private val files: List<KtFile>,
|
||||
val program: JsProgram,
|
||||
diagnostics: Diagnostics,
|
||||
private val importedModules: List<String>,
|
||||
val moduleDescriptor: ModuleDescriptor,
|
||||
val bindingContext: BindingContext,
|
||||
val packageMetadata: Map<FqName, ByteArray>
|
||||
abstract class SuccessBase(
|
||||
protected val config: JsConfig,
|
||||
protected val files: List<KtFile>,
|
||||
diagnostics: Diagnostics,
|
||||
protected val importedModules: List<String>,
|
||||
val moduleDescriptor: ModuleDescriptor,
|
||||
val bindingContext: BindingContext,
|
||||
val packageMetadata: Map<FqName, ByteArray>
|
||||
) : TranslationResult(diagnostics) {
|
||||
@Suppress("unused") // Used in kotlin-web-demo in WebDemoTranslatorFacade
|
||||
fun getCode(): String {
|
||||
val output = TextOutputImpl()
|
||||
getCode(output, sourceLocationConsumer = null)
|
||||
return output.toString()
|
||||
|
||||
abstract fun getOutputFiles(outputFile: File, outputPrefixFile: File?, outputPostfixFile: File?): OutputFileCollection
|
||||
|
||||
protected val sourceFiles = files.map {
|
||||
val virtualFile = it.originalFile.virtualFile
|
||||
|
||||
when {
|
||||
virtualFile == null -> File(it.name)
|
||||
else -> VfsUtilCore.virtualToIoFile(virtualFile)
|
||||
}
|
||||
}
|
||||
|
||||
fun getOutputFiles(outputFile: File, outputPrefixFile: File?, outputPostfixFile: File?): OutputFileCollection {
|
||||
val output = TextOutputImpl()
|
||||
|
||||
val sourceMapBuilder = SourceMap3Builder(outputFile, output, config.sourceMapPrefix)
|
||||
val sourceMapBuilderConsumer =
|
||||
if (config.configuration.getBoolean(JSConfigurationKeys.SOURCE_MAP)) {
|
||||
val sourceMapContentEmbedding = config.sourceMapContentEmbedding
|
||||
val pathResolver = SourceFilePathResolver.create(config)
|
||||
SourceMapBuilderConsumer(
|
||||
File("."),
|
||||
sourceMapBuilder,
|
||||
pathResolver,
|
||||
sourceMapContentEmbedding == SourceMapSourceEmbedding.ALWAYS,
|
||||
sourceMapContentEmbedding != SourceMapSourceEmbedding.NEVER)
|
||||
}
|
||||
else {
|
||||
null
|
||||
}
|
||||
|
||||
getCode(output, sourceMapBuilderConsumer)
|
||||
if (sourceMapBuilderConsumer != null) {
|
||||
sourceMapBuilder.addLink()
|
||||
}
|
||||
val code = output.toString()
|
||||
|
||||
val prefix = outputPrefixFile?.readText() ?: ""
|
||||
val postfix = outputPostfixFile?.readText() ?: ""
|
||||
val sourceFiles = files.map {
|
||||
val virtualFile = it.originalFile.virtualFile
|
||||
|
||||
when {
|
||||
virtualFile == null -> File(it.name)
|
||||
else -> VfsUtilCore.virtualToIoFile(virtualFile)
|
||||
}
|
||||
}
|
||||
|
||||
val jsFile = SimpleOutputFile(sourceFiles, outputFile.name, prefix + code + postfix)
|
||||
val outputFiles = arrayListOf<OutputFile>(jsFile)
|
||||
|
||||
protected fun metadataFiles(outputFile: File): List<OutputFile> {
|
||||
if (config.configuration.getBoolean(JSConfigurationKeys.META_INFO)) {
|
||||
val metaFileName = KotlinJavascriptMetadataUtils.replaceSuffix(outputFile.name)
|
||||
val moduleDescription = JsModuleDescriptor(
|
||||
@@ -121,12 +87,74 @@ abstract class TranslationResult protected constructor(val diagnostics: Diagnost
|
||||
val metaFileContent = serializedMetadata.asString()
|
||||
val sourceFilesForMetaFile = ArrayList(sourceFiles)
|
||||
val jsMetaFile = SimpleOutputFile(sourceFilesForMetaFile, metaFileName, metaFileContent)
|
||||
outputFiles.add(jsMetaFile)
|
||||
|
||||
for (serializedPackage in serializedMetadata.serializedPackages()) {
|
||||
outputFiles.add(kjsmFileForPackage(serializedPackage.fqName, serializedPackage.bytes))
|
||||
return listOf(jsMetaFile) + serializedMetadata.serializedPackages().map { serializedPackage ->
|
||||
kjsmFileForPackage(serializedPackage.fqName, serializedPackage.bytes)
|
||||
}
|
||||
} else {
|
||||
return emptyList()
|
||||
}
|
||||
}
|
||||
|
||||
private fun kjsmFileForPackage(packageFqName: FqName, bytes: ByteArray): SimpleOutputBinaryFile {
|
||||
val ktFiles = (bindingContext.get(BindingContext.PACKAGE_TO_FILES, packageFqName) ?: emptyList())
|
||||
val sourceFiles = ktFiles.map { VfsUtilCore.virtualToIoFile(it.virtualFile) }
|
||||
val relativePath = config.moduleId +
|
||||
VfsUtilCore.VFS_SEPARATOR_CHAR +
|
||||
JsSerializerProtocol.getKjsmFilePath(packageFqName)
|
||||
return SimpleOutputBinaryFile(sourceFiles, relativePath, bytes)
|
||||
}
|
||||
}
|
||||
|
||||
class Success(
|
||||
config: JsConfig,
|
||||
files: List<KtFile>,
|
||||
val program: JsProgram,
|
||||
diagnostics: Diagnostics,
|
||||
importedModules: List<String>,
|
||||
moduleDescriptor: ModuleDescriptor,
|
||||
bindingContext: BindingContext,
|
||||
packageMetadata: Map<FqName, ByteArray>
|
||||
) : SuccessBase(config, files, diagnostics, importedModules, moduleDescriptor, bindingContext, packageMetadata) {
|
||||
@Suppress("unused") // Used in kotlin-web-demo in WebDemoTranslatorFacade
|
||||
fun getCode(): String {
|
||||
val output = TextOutputImpl()
|
||||
getCode(output, sourceLocationConsumer = null)
|
||||
return output.toString()
|
||||
}
|
||||
|
||||
override fun getOutputFiles(outputFile: File, outputPrefixFile: File?, outputPostfixFile: File?): OutputFileCollection {
|
||||
val output = TextOutputImpl()
|
||||
|
||||
val sourceMapBuilder = SourceMap3Builder(outputFile, output, config.sourceMapPrefix)
|
||||
val sourceMapBuilderConsumer =
|
||||
if (config.configuration.getBoolean(JSConfigurationKeys.SOURCE_MAP)) {
|
||||
val sourceMapContentEmbedding = config.sourceMapContentEmbedding
|
||||
val pathResolver = SourceFilePathResolver.create(config)
|
||||
SourceMapBuilderConsumer(
|
||||
File("."),
|
||||
sourceMapBuilder,
|
||||
pathResolver,
|
||||
sourceMapContentEmbedding == SourceMapSourceEmbedding.ALWAYS,
|
||||
sourceMapContentEmbedding != SourceMapSourceEmbedding.NEVER
|
||||
)
|
||||
} else {
|
||||
null
|
||||
}
|
||||
|
||||
getCode(output, sourceMapBuilderConsumer)
|
||||
if (sourceMapBuilderConsumer != null) {
|
||||
sourceMapBuilder.addLink()
|
||||
}
|
||||
val code = output.toString()
|
||||
|
||||
val prefix = outputPrefixFile?.readText() ?: ""
|
||||
val postfix = outputPostfixFile?.readText() ?: ""
|
||||
|
||||
val jsFile = SimpleOutputFile(sourceFiles, outputFile.name, prefix + code + postfix)
|
||||
val outputFiles = arrayListOf<OutputFile>(jsFile)
|
||||
|
||||
outputFiles += metadataFiles(outputFile)
|
||||
|
||||
if (sourceMapBuilderConsumer != null) {
|
||||
sourceMapBuilder.skipLinesAtBeginning(StringUtil.getLineBreakCount(prefix))
|
||||
@@ -138,17 +166,23 @@ abstract class TranslationResult protected constructor(val diagnostics: Diagnost
|
||||
return SimpleOutputFileCollection(outputFiles)
|
||||
}
|
||||
|
||||
private fun kjsmFileForPackage(packageFqName: FqName, bytes: ByteArray): SimpleOutputBinaryFile {
|
||||
val ktFiles = (bindingContext.get(BindingContext.PACKAGE_TO_FILES, packageFqName) ?: emptyList())
|
||||
val sourceFiles = ktFiles.map { VfsUtilCore.virtualToIoFile(it.virtualFile) }
|
||||
val relativePath = config.moduleId +
|
||||
VfsUtilCore.VFS_SEPARATOR_CHAR +
|
||||
JsSerializerProtocol.getKjsmFilePath(packageFqName)
|
||||
return SimpleOutputBinaryFile(sourceFiles, relativePath, bytes)
|
||||
}
|
||||
|
||||
private fun getCode(output: TextOutput, sourceLocationConsumer: SourceLocationConsumer?) {
|
||||
program.accept(JsToStringGenerationVisitor(output, sourceLocationConsumer ?: NoOpSourceLocationConsumer))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class SuccessNoCode(
|
||||
config: JsConfig,
|
||||
files: List<KtFile>,
|
||||
diagnostics: Diagnostics,
|
||||
importedModules: List<String>,
|
||||
moduleDescriptor: ModuleDescriptor,
|
||||
bindingContext: BindingContext,
|
||||
packageMetadata: Map<FqName, ByteArray>
|
||||
) : SuccessBase(config, files, diagnostics, importedModules, moduleDescriptor, bindingContext, packageMetadata) {
|
||||
|
||||
override fun getOutputFiles(outputFile: File, outputPrefixFile: File?, outputPostfixFile: File?): OutputFileCollection {
|
||||
return SimpleOutputFileCollection(metadataFiles(outputFile))
|
||||
}
|
||||
}
|
||||
}
|
||||
+3
-2
@@ -22,6 +22,7 @@ import org.jetbrains.kotlin.js.backend.ast.*
|
||||
import org.jetbrains.kotlin.js.config.JsConfig
|
||||
import org.jetbrains.kotlin.js.facade.TranslationUnit
|
||||
import org.jetbrains.kotlin.protobuf.CodedInputStream
|
||||
import org.jetbrains.kotlin.psi.KtFile
|
||||
import org.jetbrains.kotlin.serialization.js.ast.JsAstDeserializer
|
||||
import org.jetbrains.kotlin.serialization.js.ast.JsAstProtoBuf
|
||||
import java.io.ByteArrayInputStream
|
||||
@@ -30,7 +31,7 @@ import java.util.HashSet
|
||||
|
||||
class AstGenerationResult(
|
||||
val units: Collection<TranslationUnit>,
|
||||
val translatedSourceFiles: Map<TranslationUnit.SourceFile, SourceFileTranslationResult>,
|
||||
val translatedSourceFiles: Map<KtFile, SourceFileTranslationResult>,
|
||||
val inlineFunctionTagMap: Map<String, TranslationUnit>,
|
||||
moduleDescriptor: ModuleDescriptor,
|
||||
config: JsConfig
|
||||
@@ -47,7 +48,7 @@ class AstGenerationResult(
|
||||
|
||||
fun getTranslationResult(unit: TranslationUnit): FileTranslationResult =
|
||||
when (unit) {
|
||||
is TranslationUnit.SourceFile -> translatedSourceFiles[unit]!!
|
||||
is TranslationUnit.SourceFile -> translatedSourceFiles[unit.file]!!
|
||||
is TranslationUnit.BinaryAst -> cache.getOrPut(unit) {
|
||||
// TODO Don't deserialize header twice
|
||||
val inlineData = JsAstProtoBuf.InlineData.parseFrom(CodedInputStream.newInstance(unit.inlineData))
|
||||
|
||||
@@ -324,7 +324,7 @@ public final class Translation {
|
||||
|
||||
Map<String, TranslationUnit> inlineFunctionTagMap = new HashMap<>();
|
||||
|
||||
Map<TranslationUnit.SourceFile, SourceFileTranslationResult> translatedSourceFiles = new LinkedHashMap<>();
|
||||
Map<KtFile, SourceFileTranslationResult> translatedSourceFiles = new LinkedHashMap<>();
|
||||
|
||||
for (TranslationUnit unit : units) {
|
||||
if (unit instanceof TranslationUnit.SourceFile) {
|
||||
@@ -344,7 +344,7 @@ public final class Translation {
|
||||
|
||||
fragment.setTests(mayBeGenerateTests(context, file, fileMemberScope));
|
||||
fragment.setMainFunction(maybeGenerateCallToMain(context, config, moduleDescriptor, fileMemberScope, mainCallParameters));
|
||||
translatedSourceFiles.put(sourceFileUnit, new SourceFileTranslationResult(fragment, staticContext.getInlineFunctionTags(), fileMemberScope));
|
||||
translatedSourceFiles.put(file, new SourceFileTranslationResult(fragment, staticContext.getInlineFunctionTags(), fileMemberScope));
|
||||
}
|
||||
else if (unit instanceof TranslationUnit.BinaryAst) {
|
||||
byte[] inlineDataArray = ((TranslationUnit.BinaryAst) unit).getInlineData();
|
||||
|
||||
Reference in New Issue
Block a user