@@ -6,9 +6,11 @@ import component.KotlinEnvironment
6
6
import org.jetbrains.kotlin.cli.js.K2JSCompiler
7
7
import org.jetbrains.kotlin.psi.KtFile
8
8
import org.springframework.stereotype.Service
9
- import kotlin.io.path.div
10
- import kotlin.io.path.readBytes
11
- import kotlin.io.path.readText
9
+ import java.io.File
10
+ import java.nio.file.Path
11
+ import kotlin.contracts.ExperimentalContracts
12
+ import kotlin.contracts.contract
13
+ import kotlin.io.path.*
12
14
13
15
@Service
14
16
class KotlinToJSTranslator (
@@ -46,28 +48,42 @@ class KotlinToJSTranslator(
46
48
fun translateWasm (
47
49
files : List <KtFile >,
48
50
debugInfo : Boolean ,
51
+ generateIncrementalCache : Boolean ,
49
52
projectType : ProjectType ,
50
- translate : (List <KtFile >, List <String >, List <String >, List <String >) -> CompilationResult <WasmTranslationSuccessfulOutput >
53
+ translate : (
54
+ List <KtFile >,
55
+ List <String >,
56
+ List <String >,
57
+ List <String >,
58
+ Boolean ,
59
+ File ? ,
60
+ Boolean ,
61
+ ) -> CompilationResult <WasmTranslationSuccessfulOutput >
51
62
): TranslationResultWithJsCode {
52
63
return try {
53
- val (dependencies, compilerPlugins, compilerPluginOptions) = when (projectType) {
54
- ProjectType .WASM -> listOf (
64
+ val parameters : WasmParameters = when (projectType) {
65
+ ProjectType .WASM -> WasmParameters (
55
66
kotlinEnvironment.WASM_LIBRARIES ,
56
67
emptyList(),
57
- emptyList()
68
+ emptyList(),
69
+ null
58
70
)
59
- ProjectType .COMPOSE_WASM -> listOf (
71
+ ProjectType .COMPOSE_WASM -> WasmParameters (
60
72
kotlinEnvironment.COMPOSE_WASM_LIBRARIES ,
61
73
kotlinEnvironment.COMPOSE_WASM_COMPILER_PLUGINS ,
62
- kotlinEnvironment.composeWasmCompilerPluginOptions
74
+ kotlinEnvironment.composeWasmCompilerPluginOptions,
75
+ kotlinEnvironment.composeWasmCache,
63
76
)
64
77
else -> throw IllegalStateException (" Wasm should have wasm or compose-wasm project type" )
65
78
}
66
79
val compilationResult = translate(
67
80
files,
68
- dependencies,
69
- compilerPlugins,
70
- compilerPluginOptions
81
+ parameters.dependencies,
82
+ parameters.plugins,
83
+ parameters.pluginOptions,
84
+ generateIncrementalCache,
85
+ parameters.cacheDir,
86
+ debugInfo,
71
87
)
72
88
val wasmCompilationOutput = when (compilationResult) {
73
89
is Compiled <WasmTranslationSuccessfulOutput > -> compilationResult.result
@@ -136,6 +152,9 @@ class KotlinToJSTranslator(
136
152
dependencies : List <String >,
137
153
compilerPlugins : List <String >,
138
154
compilerPluginOptions : List <String >,
155
+ generateIncrementalCache : Boolean ,
156
+ cacheDir : File ? ,
157
+ debugInfo : Boolean ,
139
158
): CompilationResult <WasmTranslationSuccessfulOutput > =
140
159
usingTempDirectory { inputDir ->
141
160
val moduleName = " moduleId"
@@ -156,40 +175,71 @@ class KotlinToJSTranslator(
156
175
val additionalCompilerArgumentsForKLib: List <String > = listOf (
157
176
" -Xreport-all-warnings" ,
158
177
" -Wextra" ,
159
- " -Xwasm" ,
160
- " -Xir-produce-klib-dir" ,
161
- " -libraries=${dependencies.joinToString(PATH_SEPARATOR )} " ,
162
- " -ir-output-dir=$klibPath " ,
163
- " -ir-output-name=$moduleName " ,
164
- ) + compilerPluginsArgs
178
+ " -Xwasm" ,
179
+ " -Xir-produce-klib-dir" ,
180
+ " -libraries=${dependencies.joinToString(PATH_SEPARATOR )} " ,
181
+ " -ir-output-dir=$klibPath " ,
182
+ " -ir-output-name=$moduleName " ,
183
+ ) + compilerPluginsArgs
165
184
166
- k2JSCompiler.tryCompilation(inputDir, ioFiles, filePaths + additionalCompilerArgumentsForKLib)
167
- .flatMap {
168
- k2JSCompiler.tryCompilation(inputDir, ioFiles, listOf (
169
- " -Xreport-all-warnings" ,
170
- " -Wextra" ,
171
- " -Xwasm" ,
172
- " -Xwasm-generate-wat" ,
173
- " -Xir-produce-js" ,
174
- " -Xir-dce" ,
175
- " -Xinclude=$klibPath " ,
176
- " -libraries=${dependencies.joinToString(PATH_SEPARATOR )} " ,
177
- " -ir-output-dir=${(outputDir / " wasm" ).toFile().canonicalPath} " ,
178
- " -ir-output-name=$moduleName " ,
179
- ))
180
- }
181
- .map {
182
- WasmTranslationSuccessfulOutput (
183
- jsCode = (outputDir / " wasm" / " $moduleName .uninstantiated.mjs" ).readText(),
184
- jsInstantiated = (outputDir / " wasm" / " $moduleName .mjs" ).readText(),
185
- wasm = (outputDir / " wasm" / " $moduleName .wasm" ).readBytes(),
186
- wat = (outputDir / " wasm" / " $moduleName .wat" ).readText(),
187
- )
185
+ val compileAction: (icDir: Path ? ) -> CompilationResult <WasmTranslationSuccessfulOutput > = { icDir ->
186
+ k2JSCompiler.tryCompilation(inputDir, ioFiles, filePaths + additionalCompilerArgumentsForKLib)
187
+ .flatMap {
188
+ k2JSCompiler.tryCompilation(
189
+ inputDir, ioFiles, mutableListOf (
190
+ " -Xreport-all-warnings" ,
191
+ " -Wextra" ,
192
+ " -Xwasm" ,
193
+ " -Xir-produce-js" ,
194
+ " -Xinclude=$klibPath " ,
195
+ " -libraries=${dependencies.joinToString(PATH_SEPARATOR )} " ,
196
+ " -ir-output-dir=${(outputDir / " wasm" ).toFile().canonicalPath} " ,
197
+ " -ir-output-name=$moduleName " ,).also {
198
+ if (debugInfo) it.add(" -Xwasm-generate-wat" )
199
+ if (compileWithCacheDir(generateIncrementalCache, icDir)) {
200
+ it.add(" -Xcache-directory=${icDir.normalize().absolutePathString()} " )
201
+ } else {
202
+ it.add(" -Xir-dce" )
203
+ }
204
+ }
205
+ )
206
+ }
207
+ .map {
208
+ WasmTranslationSuccessfulOutput (
209
+ jsCode = (outputDir / " wasm" / " $moduleName .uninstantiated.mjs" ).readText(),
210
+ jsInstantiated = (outputDir / " wasm" / " $moduleName .mjs" ).readText(),
211
+ wasm = (outputDir / " wasm" / " $moduleName .wasm" ).readBytes(),
212
+ wat = if (debugInfo) (outputDir / " wasm" / " $moduleName .wat" ).readText() else null ,
213
+ )
214
+ }
215
+ }
216
+
217
+ if (generateIncrementalCache) {
218
+ compileAction(cacheDir!! .toPath())
219
+ } else {
220
+ val cacheDirPath = cacheDir?.toPath()
221
+ if (compileWithCacheDir(generateIncrementalCache = false , cacheDirPath)) {
222
+ usingTempDirectory { tmpDir ->
223
+ val cachesDir = tmpDir.resolve(" caches" ).normalize()
224
+ cacheDirPath.toFile().copyRecursively(cachesDir.toFile())
225
+ compileAction(cachesDir)
226
+ }
227
+ } else {
228
+ compileAction(null )
188
229
}
230
+ }
189
231
}
190
232
}
191
233
}
192
234
235
+ @OptIn(ExperimentalContracts ::class )
236
+ private fun compileWithCacheDir (generateIncrementalCache : Boolean , cacheDir : Path ? ): Boolean {
237
+ contract {
238
+ returns() implies (cacheDir != null )
239
+ }
240
+ return cacheDir != null && (generateIncrementalCache || cacheDir.exists())
241
+ }
242
+
193
243
private fun String.withMainArgumentsIr (arguments : List <String >): String {
194
244
val mainIrFunction = """
195
245
| function mainWrapper() {
0 commit comments